Akka actors fails to initialize - java

I have simple application with Spring Boot + Akka. Rarely application fails to start with error message pointing to actor creation:
<!-- language-all: java -->
akka.actor.ActorInitializationException: akka://AkkaSystem/user/MyActor: exception during creation
I have following configuration of Spring and Akka:
Actor class
#Scope(SCOPE_PROTOTYPE)
#Component("MyActor")
public class MyActor extends UntypedActor {
....
}
SpringActorProducer class
public class SpringActorProducer implements IndirectActorProducer {
final ApplicationContext applicationContext;
final String actorBeanName;
public SpringActorProducer(ApplicationContext applicationContext,
String actorBeanName) {
this.applicationContext = applicationContext;
this.actorBeanName = actorBeanName;
}
#Override
public Actor produce() {
return (Actor) applicationContext.getBean(actorBeanName);
}
#Override
public Class<? extends Actor> actorClass() {
return (Class<? extends Actor>) applicationContext.getType(actorBeanName);
}
}
AkkaSpringExtension class
#Component
public class AkkaSpringExtension implements Extension {
private ApplicationContext applicationContext;
public void initialize(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
public Props props(String actorBeanName) {
return Props.create(SpringActorProducer.class, applicationContext, actorBeanName);
}
}
and configuration class
#Configuration
public class AkkaConfiguration {
#Autowired
private ApplicationContext applicationContext;
#Autowired
private AkkaSpringExtension springExtension;
#Bean
public ActorSystem actorSystem() {
ExecutorService executor = Executors.newCachedThreadPool();
DelegatingSecurityContextExecutorService executorService = new DelegatingSecurityContextExecutorService(executor);
ExecutionContext ec = ExecutionContexts.fromExecutorService(executorService);
ActorSystem system = ActorSystem.create("AkkaSystem", customAkkaConfiguration(), this.getClass().getClassLoader(), ec);
springExtension.initialize(applicationContext);
return system;
}
#Bean
public Config customAkkaConfiguration() {
return ConfigFactory.load();
}
}
After that I'm creating an actor in body of my service:
private ActorRef myActor;
#Autowired
private ActorSystem actorSystem;
#Autowired
private AkkaSpringExtension springExtension;
public void afterPropertiesSet() throws Exception {
myActor = actorSystem.actorOf(springExtension.props("MyActor"), "MyActor");
}
Usually all works as expected but sometimes an exception occurs (maybe 1 from 20 server startups):
MyActor[ERROR] [09/19/2016 10:14:07.705] [pool-3-thread-1] [akka://AkkaSystem/user/MyActor] Error creating bean with name 'MyActor': Injection of autowired dependencies failed; nested exception is java.lang.IllegalStateException: About-to-be-created singleton instance implicitly appeared through the creation of the factory bean that its bean definition points to
akka.actor.ActorInitializationException: akka://AkkaSystem/user/MyActor: exception during creation
at akka.actor.ActorInitializationException$.apply(Actor.scala:174)
at akka.actor.ActorCell.create(ActorCell.scala:607)
at akka.actor.ActorCell.invokeAll$1(ActorCell.scala:461)
at akka.actor.ActorCell.systemInvoke(ActorCell.scala:483)
at akka.dispatch.Mailbox.processAllSystemMessages(Mailbox.scala:282)
at akka.dispatch.Mailbox.run(Mailbox.scala:223)
at org.springframework.security.concurrent.DelegatingSecurityContextRunnable.run(DelegatingSecurityContextRunnable.java:83)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1153)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.lang.Thread.run(Thread.java:785)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'MyActor': Injection of autowired dependencies failed; nested exception is java.lang.IllegalStateException: About-to-be-created singleton instance implicitly appeared through the creation of the factory bean that its bean definition points to
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:355)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1214)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:543)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:325)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1076)
at com.swissre.cih.configuration.akka.SpringActorProducer.produce(SpringActorProducer.java:17)
at akka.actor.Props.newActor(Props.scala:213)
at akka.actor.ActorCell.newActor(ActorCell.scala:562)
at akka.actor.ActorCell.create(ActorCell.scala:588)
... 8 more
Caused by: java.lang.IllegalStateException: About-to-be-created singleton instance implicitly appeared through the creation of the factory bean that its bean definition points to
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:378)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1123)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1018)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.getSingletonFactoryBeanForTypeCheck(AbstractAutowireCapableBeanFactory.java:865)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.getTypeForFactoryBean(AbstractAutowireCapableBeanFactory.java:796)
at org.springframework.beans.factory.support.AbstractBeanFactory.isTypeMatch(AbstractBeanFactory.java:544)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doGetBeanNamesForType(DefaultListableBeanFactory.java:449)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanNamesForType(DefaultListableBeanFactory.java:425)
at org.springframework.beans.factory.BeanFactoryUtils.beanNamesForTypeIncludingAncestors(BeanFactoryUtils.java:220)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1199)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1054)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1019)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:566)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:349)
... 18 more
Any ideas what can be wrong?

I moved actor initialization from afterPropertiesSet to a regular method, so actors will be initialized at first method call and initialization failure gone.

Related

coundn't get bean when running a jar packed from a springboot project

I can run my springboot project in IDEA nicely but when packed it to a jar and run with the java command, just got the java.lang.NullPointerException when getting a bean from spring context.
the first class which just got errors:
#Service
public class MdspiImpl extends CThostFtdcMdSpi {
public MdspiImpl(CThostFtdcMdApi mdapi) {
m_mdapi = mdapi;
logger.info("MdspiImpl is creating...");
***mdr = SpringContextUtil.getBean("marketDataRobot");//this is the error code***
}
}
the second class:
#Service
public class MarketDataRobot {
}
the SpringContextUtil class:
#Component("SpringContextUtil")
public class SpringContextUtil implements ApplicationContextAware {
private static ApplicationContext applicationContext;
public static <T> T getBean(String name) {
return (T) applicationContext.getBean(name);
}
}
the gradle file:
jar {
baseName = 'programmingTrading'
version = '0.1.0'
manifest {
attributes 'Main-Class': 'com.blackHole.programmingTrading'
}
}
the running exception:
WARN main[AbstractApplicationContext.java:557 Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'mdspiImpl' defined in URL [jar:file:/E:/workspace/simuPrd/programmingTrading-0.0.1-SNAPSHOT.jar!/BOOT-INF/classes!/com/blackHole/programmingTrading/infrastructure/MdspiImpl.class]: Bean instantiation via constructor failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.blackHole.programmingTrading.infrastructure.MdspiImpl]: Constructor threw exception; nested exception is java.lang.NullPointerException]
[com.blackHole.programmingTrading.infrastructure.MdspiImpl]: Constructor threw exception; nested exception is java.lang.NullPointerException
at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:184)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:117)
at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:300)
... 27 common frames omitted
Caused by: java.lang.NullPointerException: null
at com.blackHole.programmingTrading.SpringContextUtil.getBean(SpringContextUtil.java:35)
at com.blackHole.programmingTrading.infrastructure.MdspiImpl.<init>(MdspiImpl.java:46)
It also stem from another problem: #Autowired annotation doesn't work...
when using like this:
#Component
public class Scu{
}
in another class:
#Autowired
private Scu scu;
logger.info(String.format("MdspiImpl is creating...[%s]", scu.toString()));
will get a java.lang.NullPointerException: null
spring-boot configuration like this:
#SpringBootApplication
public class ProgrammingTrading {
public static void main(String[] args) {
SpringApplication.run(ProgrammingTrading.class, args);
}
}
that is part of reasons of using SpringContextUtil to get the bean...
thanks a lot!
SpringContextUtil shouldn't be a accessed statically like you are doing... Since you define it as a #Component do the following;
#Service
public class MdspiImpl extends CThostFtdcMdSpi {
#Autowired
private SpringContextUtil springContextUtil;
public MdspiImpl(CThostFtdcMdApi mdapi) {
m_mdapi = mdapi;
logger.info("MdspiImpl is creating...");
***mdr = springContextUtil.getBean("marketDataRobot");
}
}
Due to SpringContextUtil not being injected via Spring, but simply accessed statically, the applicationContext inside of it is ignored and is null in your case.
Also remove the static modifier;
#Component
public class SpringContextUtil implements ApplicationContextAware {
private ApplicationContext applicationContext;
// include getter/setter for applicationContext as well
public <T> T getBean(String name) {
return (T) applicationContext.getBean(name);
}
}
edit
The trouble from the latest example project;
#Service
public class ExampleService {
#Autowired
private Logger logger;
public ExampleService() {
this.logger=logger;
logger.info("Im working");
}
}
Here the Logger will be null, when the ExampleService constructor is triggered, since the constructor is called before the injection starts, but you can merge this behaviour if you incorporate the injection through the said constructor as follows;
#Service
public class ExampleService {
private final Logger logger;
public ExampleService(Logger logger) {
this.logger = logger;
logger.info("Im working");
}
}
Works perfectly without any trouble...
You should never be accessing beans programmatically like you did with this SpringContextUtil, just inject MarketDataRobot in the constructor of MdspiImpl and you’re good to go (since it’s annotated with #Service). The preferred way is to use constructor injection instead of field injection, which will make it easier for you to write unit tests. You can also get rid of #Autowired if you have only one constructor.

Autowiring fails in Junit testing and spring #configuration

I have two #Configuration classes. I need a bean from one configuration class to another. I have autowired the configuration 1 into 2. All works fine. When executing the unit testing, am getting the below exception.
setUpContext(com.trafigura.titan.framework.services.messaging.loader.SpringLoadTest)
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'com.xxx.MessagingServicesConfig': Injection of autowired dependencies failed;
nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.xxx.EMSJMSConfig com.xxx.MessagingServicesConfig.emsJmsConfig;
nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type[com.xxx.EMSJMSConfig] found for dependency:
expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
Is there anything I need to do additionally to make this working?
Below is the setup for testing.
#Configuration
#Import({MessagingServicesConfig.class,...,EMSJMSConfig.class
})
public class MessagingConfig {}
#Profile("EMS-MESSAGING")
#Configuration
public class EMSJMSConfig {
#Bean
public javax.jms.ConnectionFactory jmsSubscriberConnectionFactory() throws JMSException {
SingleConnectionFactory singleConnectionFactory = new SingleConnectionFactory(tibjmsConnectionFactory());
return singleConnectionFactory;
}
}
#Configuration
public class MessagingServicesConfig {
#Autowired
private EMSJMSConfig emsJmsConfig;
#Bean(destroyMethod = "shutdown")
public MessagingService messagingService() throws JMSException {
...
ConnectionFactory cf=emsJmsConfig.jmsSubscriberConnectionFactory(); // Getting NPE at this line.
}
}
and finally the test class,
public class MessagingServicesConfigTest {
private MessagingServicesConfig config;
private EMSJMSConfig emsJmsConfig;
#BeforeMethod
public void setUp() throws Exception {
config = new MessagingServicesConfig();
... //what needs to be done here to have the EMSJMSConfig
}
#Test
public void testBuildsCorrectService() throws JMSException {
MessagingService service = config.messagingService();
...
}
}
By calling new you're creating object yourself, Spring doesn't know anything about it.
Moreover, you should have a test configuration which will be aware of your beans.
Use an appropriate Runner to load SpringContext.
#ContextConfiguration(classes = TestConfig.class)
#RunWith(SpringRunner.class)
class Tests {
#Autowired // if needed
private MessagingServicesConfig config;
}
While in TestConfig you can create beans or import configuration from the Application:
#Configuration
#Import({MessagingServicesConfig.class})
public class TestConfig {}
#Configuration
#Import({EMSJMSConfig.class})
public class MessagingServicesConfig {}
Or you can refer to your config classes directly:
#ContextConfiguration(classes = {MessagingServicesConfig.class, EMSJMSConfig.class})

How could I get #FeignClient bean when spring boot application initializing

I need use a bean inject with #Component #FeignClient(name = "xxx") when my spring boot application initializing, but it always throws exception like this:
20180706 10:18:40,043 WARN [main]
[org.springframework.context.annotation.AnnotationConfigApplicationContext]
Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'feignContract' defined in org.springframework.cloud.netflix.feign.FeignClientsConfiguration: Unsatisfied dependency expressed through method 'feignContract' parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'feignConversionService' defined in org.springframework.cloud.netflix.feign.FeignClientsConfiguration: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.format.support.FormattingConversionService]: Factory method 'feignConversionService' threw exception; nested exception is java.lang.StackOverflowError
my feignClient code:
#Component
#FeignClient(name = "domain-account")
public interface IDomainService {
#RequestMapping(value = "/userInfos", method = RequestMethod.GET)
public String getUserInfos(#QueryMap Map<String, Object> condition);
}
ApplicationListenner code:
public class GlobalInit implements ApplicationListener<ContextRefreshedEvent> {
#Override
public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
System.out.println("======== GlobalInit ========");
IDomainService domainService = contextRefreshedEvent.getApplicationContext().getBean(IDomainService.class);
System.out.println("*********************" + domainService);
GlobalInitManager.getInstance().doInit();
}
}
It's not entirely clear for me what you try to do with the GlobalInit but the 'standard' way of designing your Feign client in Spring Boot would the following:
#SpringBootApplication
#EnableFeignClients
#EnableHypermediaSupport(type = EnableHypermediaSupport.HypermediaType.HAL)
#EnableCaching
public class MyHelloWorldApplication {
public static void main(String[] args) {
SpringApplication.run(MyHelloWorldApplication.class, args);
}
}
#Component
public class HelloWorldServiceImpl implements HelloWorldService {
#Autowired
private IDomainService iDomainService ;
public void myMethod() {
String userinfo = iDomainService.getUserInfos(...);
}
}
Hopefully this helps.
All the best,
Wim

spring injection bean which inherits from interface

I have config with some #Bean annotations and it works.
But if I change the bean to inherit from interface it isn't work. Do I need special annotations o something like?
config class snippet without imports
#Configuration
#ComponentScan("io.github.aaa4")
//#ComponentScan({ "io.github.aaa4.dao", "io.github.aaa4.entity","io.github.aaa4.Servlets"})
#EnableTransactionManagement
public class AppConfig {
#Bean
public ComboPooledDataSource myDataSource() throws PropertyVetoException {
ComboPooledDataSource ds = new ComboPooledDataSource();
ds.setDriverClass("com.mysql.jdbc.Driver");
ds.setJdbcUrl("jdbc:mysql://localhost:3306/emp?useSSL=false");
ds.setUser("emp");
ds.setPassword("emp");
ds.setMinPoolSize(2);
ds.setMaxPoolSize(20);
ds.setMaxIdleTime(30000);
return ds;
}
#Bean
public LocalSessionFactoryBean mySessionFactory() throws PropertyVetoException {
LocalSessionFactoryBean sf = new LocalSessionFactoryBean();
Properties hibernateProperties = new Properties();
hibernateProperties.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQLDialect");
hibernateProperties.setProperty("hibernate.show_sql", "true");
sf.setDataSource(myDataSource());
sf.setPackagesToScan("io.github");
sf.setHibernateProperties(hibernateProperties);
return sf;
}
#Bean
#Autowired
public HibernateTransactionManager myTransactionManager(SessionFactory sessionFactory) {
HibernateTransactionManager htm = new HibernateTransactionManager();
htm.setSessionFactory(sessionFactory);
return htm;
}
#Bean
public UserDao userDaoImpl() {
return new UserDaoImpl();
}
#Bean
public DBService dBServiceImpl() {
return new DBServiceImpl();
}
}
serviceImpl snippet
#Service
public class DBServiceImpl implements DBService {
//inject user DAO
#Autowired
private UserDao userDao;
#Transactional
public void addUser(MyUser user) {
userDao.createUser(user);
}
#Transactional
public List<MyUser> getUserList() {
return userDao.getusers();
}
#Transactional
public void deleteUser(int theId) {
userDao.deleteUser(theId);
}
}
main class
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
DBServiceImpl service = ctx.getBean(DBServiceImpl.class);
MyUser user = new MyUser("alice", "and her passwd");
System.out.println("this is the user:" + user);
service.addUser(user);
service.addUser(user);
service.addUser(user);
service.addUser(user);
System.out.println("User added!");
service.deleteUser(2);
System.out.println("user number id = 2 deleted");
List<MyUser> userList = service.getUserList();
for (MyUser users : userList)
System.out.println(users);
ctx.close();
}
}
stacktrace with problem
INFO: Using DataSource [com.mchange.v2.c3p0.ComboPooledDataSource[ identityToken -> 1hge1459o1fr6qmlst9469|42e99e4a, dataSourceName -> 1hge1459o1fr6qmlst9469|42e99e4a ]] of Hibernate SessionFactory for HibernateTransactionManager
Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'io.github.aaa4.services.DBServiceImpl' available
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:353)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:340)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1093)
at io.github.aaa4.Main.main(Main.java:30)
with annotation #EnableAspectJAutoProxy(proxyTargetClass = true) above the config class
WARNING: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.aop.config.internalAutoProxyCreator': Initialization of bean failed; nested exception is java.lang.NoClassDefFoundError: org/aspectj/lang/annotation/Around
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.aop.config.internalAutoProxyCreator': Initialization of bean failed; nested exception is java.lang.NoClassDefFoundError: org/aspectj/lang/annotation/Around
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:564)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)
at org.springframework.context.support.PostProcessorRegistrationDelegate.registerBeanPostProcessors(PostProcessorRegistrationDelegate.java:223)
at org.springframework.context.support.AbstractApplicationContext.registerBeanPostProcessors(AbstractApplicationContext.java:702)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:527)
at org.springframework.context.annotation.AnnotationConfigApplicationContext.<init>(AnnotationConfigApplicationContext.java:84)
at io.github.aaa4.Main.main(Main.java:14)
Caused by: java.lang.NoClassDefFoundError: org/aspectj/lang/annotation/Around
at org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory.<clinit>(ReflectiveAspectJAdvisorFactory.java:77)
at org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator.initBeanFactory(AnnotationAwareAspectJAutoProxyCreator.java:78)
at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.setBeanFactory(AbstractAdvisorAutoProxyCreator.java:60)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeAwareMethods(AbstractAutowireCapableBeanFactory.java:1647)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1615)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555)
... 10 more
Caused by: java.lang.ClassNotFoundException: org.aspectj.lang.annotation.Around
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
... 16 more
Try to use an interface instead of an implementation
DBService service = ctx.getBean(DBService.class);
You have #Transactional annotations on your service methods. All #Transactional annotations should be scanned at startup time and the targeted methods should become transactional. To add transactional behavior Spring creates a proxy for your class. That's why you can't get your bean.
I think,you should make changes in this line DBServiceImpl service = ctx.getBean(DBServiceImpl.class); to DBService service = ctx.getBean(DBService.class);
for reference check spring doc Using the #Bean annotation Spring DOC
"What's important to keep in mind is that, if the transactional bean is implementing an interface, by default the proxy will be a Java Dynamic Proxy. This means that only external method calls that come in through the proxy will be intercepted."
Refer https://www.baeldung.com/transaction-configuration-with-jpa-and-spring.
Following should make it work:
DBService service = ctx.getBean(DBService.class);

Spring Bean is not autowired

I have a problem with Spring bean DefaultConfigurationService initialization that is extended from abstract class. I am totally stuck.
Class hiearchy is as follows:
public interface ConfigurationService {
TaxPayer getTaxPayer();
}
This class is mentioned to be useful for services that need to be initialized:
public abstract class BaseInitializationAwareService {
private boolean initialized = false;
public abstract void initialize();
protected void checkInitialization() {
if (!initialized) {
initialize();
}
}
protected void setInitialized() {
this.initialized = true;
}
}
This class acts as base class for Configuration service.
public abstract class BaseConfigurationService extends BaseInitializationAwareService implements ConfigurationService {
}
And with this bean, that acts as a configuration service, is a problem:
public class DefaultConfigurationService extends BaseConfigurationService {
private TaxPayerService taxPayerService;
#Autowired
public void setTaxPayerService(TaxPayerService taxPayerService) {
Assert.notNull(taxPayerService);
this.taxPayerService = taxPayerService;
}
public void initialize() {
Optional<TaxPayer> dbtaxPayer = taxPayerService.getActiveTaxPayer();
if (!dbtaxPayer.isPresent()) {
throw new IllegalStateException("Tax payer setting not found!");
}
this.taxPayer = dbtaxPayer.get();
setInitialized();
}
// the rest omitted...
}
when I'm creating DefaultConfigurationService bean:
#Bean
public BaseConfigurationService configurationService() {
DefaultConfigurationService configurationService = new DefaultConfigurationService();
configurationService.initialize();
return configurationService;
}
then taxPayerService in DefaultConfigurationService is null - it seems that is not autowired.
Can it be connected to the fact that DefaultConfigurationService is extended from abstract class?
TaxPayer service bean:
#Bean
public TaxPayerService taxPayerService() {
DatabaseTaxPayerService taxPayer = new DatabaseTaxPayerService();
return taxPayer;
}
This bean is probably never initialized...
Thats is a exception:
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'webSecurityConfig.ApiSecurity':
Unsatisfied dependency expressed through method
'setContentNegotationStrategy' parameter 0; nested exception is
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name
'org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration':
Unsatisfied dependency expressed through method 'setConfigurers'
parameter 0; nested exception is
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'passwordRecoverController': Unsatisfied
dependency expressed through method 'setUserService' parameter 0;
nested exception is
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'defaultUserService': Unsatisfied
dependency expressed through method 'setNotificationService' parameter
0; nested exception is
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'notificationService': Unsatisfied
dependency expressed through method 'setConfigurationService'
parameter 0; nested exception is
org.springframework.beans.factory.BeanCreationException: Error
creating bean with name 'configurationService' defined in class path
resource [com.example.config/AppConfig.class]: Bean instantiation via
factory method failed; nested exception is
org.springframework.beans.BeanInstantiationException: Failed to
instantiate [com.example.services.BaseConfigurationService]: Factory
method 'configurationService' threw exception; nested exception is
java.lang.NullPointerException
For example, bean that needs BaseConfigurationService:
public class EmailNotificationService extends BaseService implements NotificationService {
private BaseConfigurationService configurationService;
#Autowired
public void setConfigurationService(BaseConfigurationService configurationService) {
Assert.notNull(configurationService);
this.configurationService = configurationService;
}
// the rest omitted...
}
#update 1
Bean initialization example with internal dependencies to another beans:
#Bean
public TransactionDataService transactionDataService() {
return new DefaultTransactionDataService();
}
and DefaultTransactionDataService:
public class DefaultTransactionDataService implements TransactionDataService {
private PrivateKeyService privateKeyService;
#Autowired
public void setPrivateKeyService(PrivateKeyService privateKeyService) {
Assert.notNull(privateKeyService);
this.privateKeyService = privateKeyService;
}
}
and bean dependency
#Bean
public PrivateKeyService privateKeyService() {
return new DefaultPrivateKeyAwareService();
}
and it works.
It is related to your instruction to Spring how to initialize your bean:
#Bean is used to explicitly declare a single bean, rather than letting Spring do it automatically as above. It decouples the declaration of the bean from the class definition, and lets you create and configure beans exactly how you choose.
So when you create instance of your class manually your have to set all class field manually as well.
It can be done like this:
#Bean
public BaseConfigurationService configurationService() {
DefaultConfigurationService configurationService = new DefaultConfigurationService();
configurationService.setTaxPayerService(taxPayerService());
configurationService.initialize();
return configurationService;
}
Or move dependency directly to constructor, so dependency of your DefaultConfigurationService will be more obvious:
#Bean
public BaseConfigurationService configurationService() {
DefaultConfigurationService configurationService = new DefaultConfigurationService(taxPayerService());
configurationService.initialize();
return configurationService;
}
Good description

Categories