I made a simple app with the following dependency tree for components:
Service1 injects Service2(via constructor)
Service2 injects SomeContext(via setter)
SomContext injects Service1(via setter)
Advisor is for Service1
So when spring tries to construct Service1 or Service2 it automatically tries to apply advise, but there is a check in spring - isCurrentlyInCreation (in BeanFactoryAdvisorRetrievalHelper.java), so the bean for which it tries to apply advise is still it creation and skips advise applying.
I know that recurse of bean is a bad way of design but it is hard to decouple now and refactor.
I fix this issue with the help of factorybean for SomeContext and loading of Service1 when needed via applicationcontext(applicationcontextaware), but maybe someone knows better solution?
You can workaround this if you apply compile time weaving instead of load time weaving. Here are two posts that can get you started:
Spring, Aspects, #Configurable and Compile Time Weaving using maven
Spring #Transactional: Verifying transaction support / Local method calls
Related
I'm working on an integration with an older library so that it can use Spring Boot testing, and for that I need to register a certain bean very early in the process, so that an ApplicationListener<ApplicationReadyEvent> can add a PropertySource to the Environment.
This works fine in the normal startup, but when using the #SpringBootTest annotation I need to be able to inspect the TestContext very early and add it to the testing BootstrapContext, so that the application listener can access it also in the integration tests.
But I can't find a good way to add bean instances to the test BootstrapContext apart from specifying an initializer class in the spring.factories files, or am I missing something here?
I have been looking into using #BootstrapWith and subclassing SpringBootContextBootstrapper, but can't seem to find a way to add some kind of BootstrapregistryInitializer-like functions?
Our Java Web application loads with over 1000 plugins that are all registered by us as Spring beans using the ApplicationContext#registerBeanDefinition() method. These beans often have other dependencies which we also register as spring beans using the same method (for a total of about 7,000 Spring bean definitions...not including our core application code).
The problem is that the startup time is long (approximately 6.5 minutes of just plugin bean definition loading). We would prefer to spread this load time out over a much longer period while our app is actually processing other requests utilizing plugins that have already had their bean definitions registered. Most of the plugins are seldom used. Thus, we would really like to lazily register our bean definitions (this is different from lazy-init of singleton beans which we already do today). However, this seems costly with any existing Spring ApplicationContext that supports 'hot' refresh() calls (as the Spring documentation refers to it).
The Spring ApplicationContext classes that support 'hot' refresh start by destroying all of the singleton beans. Most of our plugins are singletons, so each call to refresh() would cause most of our plugins to be destroyed and then recreated...costly. If we don't call refresh, then our newly loaded plugin beans will not be post-processed (e.g., AOP, etc...).
We can guarantee that when we are forced to load another plugin, we will also load any of its dependencies that are not already loaded. So, we would never ben in a situation where a loaded bean definition is invalid.
It seems to me that this calls for a new type of Spring ApplicationContext that supports 'hot' refresh, but only for the purpose of adding new bean definitions. Preexisting bean definitions are not removed/reloaded, and not re-processed by BeanFactoryPostProcessors on subsequent refresh() calls, and pre-existing singletons are not destroyed!
Does this already exist?. Is there a better solution that I'm overlooking?
This sounds like you're looking for #Lazy.
4.4.4 Lazy-initialized beans
A lazy-initialized bean tells the IoC container to create a bean instance when it is first requested, rather than at startup.
I am using autowiring in one of my projects. #autowiring is working fine in the controller, but I need to use same autowiring object in some other class, which is used as task class for quartz. Autowiring is not working there.
I tried this code listed below, but it did not succeed. In all attempts it's getting null for readXmlDao.
#Repository("updateTeam")
public class TeamUpdate {
#Autowired
#Qualifier("readXmlDao")
ReadXmlDao readXmlDao;
Please suggest a solution, thanks.
Autowire works in spring context (class instances managed by spring). Quartz creates its own contexts (creates its own instances). Spring do not have to know about these classes and its why autowires not working on them.
It is more spring/quartz configuration issue, than class annotation issue.
Spring will never leave an #Autowired target null. If it's processing the bean and can't find a match it will throw exceptions.
Since you are telling us it's null, the only possibility is that Spring is not managing your object. You're either creating a TeamUpdate object manually or some other process (not Spring) is creating it for you.
In your spring-servlet file make sure you are scanning the correct packages.
<context:component-scan base-package="your package here"/>
A lot of times you might have your controllers and your repositories in different packages. Make sure to scan both.
you might want to try this approach for using spring managed beans in a non-spring managed object.
http://www.javacodegeeks.com/2015/03/using-spring-managed-bean-in-non-managed-object.html
I have a 3-tier application: web-service, service-layer and domain-layer. The web service is present in a web application (WAR). The service-layer and domain-layer are two JAR projects. The dependencies are:
web-service --> service-layer --> domain-layer
In the service layer, the services are annotated with #Service. In the domain-layer, the DAOs are annotated with #Repository. The web service implementation class uses the services of the service-layer JAR, so it keeps one instance of each service which is automatically injected (#Autowired).
The dependencies are well defined in my POMs. When I deploy my WAR on Tomcat, I get the following exception:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [com.mycompany.project.services.MyService] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:952)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:821)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:735)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.inject(AutowiredAnnotationBeanPostProcessor.java:551)
... 37 more
I quote from one relevant part in the Spring docs:
The scanning of classpath packages requires the presence of
corresponding directory entries in the classpath. When you build JARs
with Ant, make sure that you do not activate the files-only switch of
the JAR task.
I've checked and the service-layer JAR is present in the WEB-INF/lib directory.
Any idea?
Thanks
EDIT: I have only one context file which is located in the web-service layer project (WAR) under src/main/webapp/WEB-INF. In this context, I've enabled classpath scanning as follows:
<context:component-scan base-package="com.mycompany.project" />
The package com.mycompany.project is the base package of my project, under which there are the web-service (com.mycompany.project.server), service-layer (com.mycompany.project.services) and domain-layer (com.mycompany.project.domain) packages.
I've solved the issue. I don't understand why what I've done was causing such an issue. Each service implements an interface that defines its public methods. In my web service implementation class, the references to the services used the implementation classes and not the interfaces. I just changed them to use the interface, and I don't get the issue anymore. Could anyone explain me what's wrong with using the services implementation classes instead of the interfaces for the autowiring?
This is an answer for your EDIT:
The reason why referring to the interface worked but the concrete implementation failed is probably to do with the dynamic proxies that Spring creates for cases where you have your services annotated with #Transactional etc. What happens in such cases is that the type of your beans are not the implementation type anymore, but wrap around your impementation type. So when you have #Autowired by implementation type, it just cannot find it by type (which is the default).
Your fix is very appropriate, as a dynamic proxy continues to derive from the interfaces that you have defined for your implementation and so can inject by interface type - the reference that I have provided does a better job explaining this.
make sure you used <context:component-scan base-package="your.service.package"/>
check your autowired strategy is byName or byType; if byName, the Service annotation's name value should be right.
if problem still exist, check spring's log, it will print all found components' name, you could know the service is founded or not.
Can you show your component scanning configuration? If this is not set up correctly then Spring may not be discovering your service.
You want something like:
<context:component-scan base-package="your.service.package"/>
Edit:
I think the problem is that your #Service annotation is on the interface rather than implementation class.
If you annotate your service implementation then your web controller can use either:
#Autowired
private ExampleService service;
or
#Autowired
private ExampleServiceImpl service;
I'm using mockejb framework to mock entity beans in memory, I make a lookup, mockejb brings me a proxy for the real entity. That's working.
But I needed to get a Session Bean from the container JNDI to "understand" that. I mean, when the Session Bean make a lookup to the Entity Bean, I want it to receive the bean I've mocked, not a bean from the database.
I can't mock this Session Bean because inside the method I'm trying to mock, there's a lookup to the entity bean so, I need this method to execute normally but to receive the mocked bean when lookup.
[UPDATE]
Informations about my development environment:
I'm using IBM RSA 7.5, IBM Websphere 6.1,
I have a Web Test Project that runs in-container with Cactus, the last libs on my classpath are:
cactus-1.7.2.jar
cglib-nodep-2.1_3.jar
commons-httpclient-2.0.2.jar
commons-logging-1.0.4.jar
powermock-easymock-1.3.9-full.jar
junit-3.8.1.jar
mockejb.jar
Obs.: I've already changed to the latest powermock version with jUnit4, and tried to use EasyMock 3.0 only, and also tried EasyMock 2.x with its class extensions. None of these worked. What really intrigues me is this DefaultInstantiator configuration mentioned on EasyMock docs: http://easymock.org/EasyMock2_4_ClassExtension_Documentation.html. I wondered if that's my case (not supported JVM) and I couldn't make it work.
Thanks for helping.
"I can't mock this Session Bean because inside the method I'm trying to mock, there's a lookup to the entity bean so,"
Can't you use something like PowerMock to 'fake' the lookup? Like with a replace of methods etc.
Here is something i came across lately:
http://dave00ster.blogspot.com/2011/07/powermock-static-method-replace.html
Hope this helps,
dave00