I came across an example of #Autowired:
public class EmpManager {
#Autowired
private EmpDao empDao;
}
I was curious about how the empDao get sets since there are no setter methods and it is private.
Java allows access controls on a field or method to be turned off (yes, there's a security check to pass first) via the AccessibleObject.setAccessible() method which is part of the reflection framework (both Field and Method inherit from AccessibleObject). Once the field can be discovered and written to, it's pretty trivial to do the rest of it; merely a Simple Matter Of Programming.
Java allows you to interact with private members of a class via reflection.
Check out ReflectionTestUtils, which is very handy for writing unit tests.
No need for any setter, you just have to declare the EmpDao class with the annotation #component in order that Spring identifies it as part of the components which are contained in the ApplicationContext ...
You have 2 solutions:
To manually declare your beans in the XML file applicationContext :
<bean class="package.EmpDao" />
To use automatic detection by seeting these lines in your context file:
<context:component-scan base-package="package" />
<context:annotation-config />
AND to use the spring annotation to declare the classes that your spring container will manage as components:
#Component
class EmpDao {...}
AND to annotate its reference by #Autowired:
#Component (or #Controller, or #Service...)
class myClass {
// tells the application context to inject an instance of EmpDao here
#Autowired
EmpDao empDao;
public void useMyDao()
{
empDao.method();
}
...
}
Autowiring happens by placing an instance of one bean into the desired field in an instance of another bean. Both classes should be beans, i.e. they should be defined to live in the application context.
Spring knows the existence of the beans EmpDao and MyClass and will instantiate automatically an instance of EmpDao in MyClass.
Spring uses the CGLib API to provide autowired dependency injection.
References
Usage of CGLib forum comment by Rod Johnson
3.3.1. Injecting dependencies
Pro Spring - Analyzing Spring Dependencies
Further Reading
Introduction to the Spring Framework by Rod Johnson
Related
I want to use data mappers, logger, transfromers, etc. in my Spring web projects. Is it possible to autowire an imported (jar) utility dependency, without wrapping it in some #Component or #Service class? Do we even want to do it that way, or should we just use a static reference?
If your utils, are based on not static methods, then this is simple:
If you use java based configuration, then just declare that util in an #Bean annotated method.
#Configuration
public class YourConfig {
#Bean
public YourUtil util(){
return new YourUtil ();
}
}
in xml it could been as simple as:
<bean id="util" class="org.example.YourUtil" />
The following is true, but it is not what was asked for:
There are at least two other ways to inject beans in instances that are not created (managed) by Spring:
(1) add #Configurable annotation to this class - this requires real AspectJ (compile-time or load-time -weaving)
#see Spring Reference Chapter 7.8.1 Using AspectJ to dependency inject domain objects with Spring
#see this answer of mine https://stackoverflow.com/a/7007572/280244 for a quick "guide" to enable the #Configurable support
(2) invoke SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
#see this question and its (two highes voted answers) for some ideas how to use
You can only #Autowire a bean managed by Spring. So you have to declare your instance through some configuration : a bean in an xml file, or a #Bean method in a java configuration.
#Component are just automatically discovered and registered in the spring context.
I can not find any reason why every autowired bean are not autowired by proxy. I know that becasue #Transactional annotations do not work and I checked autowired component during debugging in eclipse. Of course every component implements some interface and I use #Autowired annotations in relation to the interface.
I have only one configuration of aop:
<tx:annotation-driven transaction-manager="transactionManager" />
I use JPA with hibernate, spring-mvc,spring-webflow, spring-security and spring-data. Interfaces which extends org.springframework.data.repository.CrudRepository are autowired by proxy. But my components are not. For example I have class MyClass which implement MyInterface:
#Service
public class MyClass implements MyInterface {
#Autowired
MyCrudReposiotry reposiotry;
....
}
If I autowire MyInterface somewhere:
#Autowired
MyInterface mi;
then mi is just reference to MyClass object, repository is refrence to proxy org.springframework.aop.framework.JdkDynamicAopProxy. Very interesting is that in testing mi is reference to proxy. My test's context does not contain web-flow and mvc configuration.
Maybe there is some indirect aop configuration which I should check. What can switch the autowiring by proxy off?
My guess is that you are scanning for the same components twice. You probably have a in your root context (for the ContextLoaderListener) and one for the DispatcherServlet. NO if the both scan for the same classes you end up with duplicated (and one proxied and one non proxied instance).
Proxying and auto wiring are independent of each other. When you use #AutoWired it finds another bean that implements the required interface and injects it. The bean instance it finds might be a normal object or a proxy - it doesn't matter to Autowired.
Proxies are created for certain beans automatically by spring. As you have noticed one scenario in which this happens is when you use #Transactional. When the spring container instantiates a bean which has the #Transactional annotation the object gets wrapped in a proxy. The actual object is replaced by the proxy in the context. This is done so that spring can intercept calls to those methods and add the begin / commit transaction calls before and after the method call. This is implemented by the spring-aop module. Any feature that relies on AOP (#Transactional, #Secured) will result in creation of a proxy.
The other case where proxies are used is to create an implementation on the fly. In case of the CRUDRepository you are required to only implement the interface. The implementation of that is created on the fly using the same proxy infrastructure.
I have a TestNG listener that implements IInvokedMethodListener. I would like to wire in a Spring bean inside this listener and use it. Unfortunately, this class is instantiated by TestNG and so Spring cannot wire anything in that is annotated using #Autowired. I tried implementing ApplicationContextAware, but that doesn't work either.
Is there a way to wire Spring beans into classes that implement IInvokedMethodListener?
ApplicationContextAware only works for Spring Beans. You can use #Configurable, but that requires AspectJ.
Here's a simple hack that should work: Add a static member to your listener class and inject it via a non-static setter.
public class MyMethodListener implements IInvokedMethodListener {
private static MyBean myBean;
#Autowired
public void setMyBean(MyBean myBean) {
MyMethodListener.myBean = myBean;
}
}
Include a bean of the required type in your application context.
The listener instantiated by TestNG will not be the same instance as the one from the Spring context, but it will have the static member set, provided that context creation has finished before TestNG instantiates the listener.
I had the same problem recently, it is basically Listeners are not maintained by spring. So I did some googling around this concept like "Injecting beans into classes not managed by spring", I got https://dzone.com/articles/autowiring-spring-beans-into-classes-not-managed-by-spring link which explains exactly the same problem and the solution. It worked for me.
I've declared my aspects using the #Aspect annotation, but the advice does not seem to get applied. The aspect works in a few other projects that I have, and the key difference seems to be that the other projects are completely wired using annotations, and this particular project is xml wired. The only bean that is annotation wired is the Aspect. So I'm wondering if spring's aspectj support, when using aspectj-autoproxy is sensitive to order that the beans are defined in the xml.
For example, will beans declared after aspectj-autoproxy in xml be considered for AOP pointcuts?
EDIT:
I moved the <aop:aspectj-autoproxy /> until after all beans are created and still no luck.
Basically my code consists of:
#Component
#Aspect
public class SomeAspect {
#Pointcut("#annotation(MyAnnotation)")
public void isX() {}
#After("isX()")
public void XX() {
System.out.println("Called aspect");
}
}
And my controller has something like:
public class XController extends AbstractCommandController {
#MyAnnotation
public void handleX(...) {
// do stuff
}
#Override
protected void handle(...) {
return handleX(...);
}
}
And then the spring xml is:
<context:component-scan base-package="package.of.some.aspect" />
<aop:aspectj-autoproxy />
<!-- the rest of the beans below -->
<bean id="someController" class="..." />
My previous projects captured and loaded all beans via the component-scan. That's what's different this time.
EDIT2:
The other difference is that the other projects are using #Controller, and #RequestMethod. And in this case I'm using a derived class of AbstractCommmandController. I'm wondering if this applies:
http://forum.springsource.org/archive/index.php/t-46637.html
Namely that I can't apply advice to any method except handleRequest().
EDIT3:
My latest try is to override handleRequest() and apply my annotation there. Under the assumption that when spring proxies my controller it will see the annotation and apply the advice, since it's calling through the public, externally called method. This still doesn't work.
I see that you are calling the method handleX directly from another method in the same class. This will not respect the annotiation, as the work of processing AOP annotations is done by a JDK proxy that wraps your class and exposes the same interfaces.
It's possible that you can work around this by using CGLIB instead of JDK proxies, but in my experience, the most reliable solution is just not to rely on any AOP annotations for methods called internally.
I would like to know if it's possible to use Spring to resolve the dependencies of an object created manually in my program. Take a look at the following class:
public class TestClass {
private MyDependency md;
public TestClass() {
}
...
public void methodThaUsesMyDependency() {
...
md.someMethod();
...
}
}
This TestClass is not a spring bean, but needs MyDependency, that is a spring bean. Is there some way I can inject this dependency through Spring, even if I instantiate TestClass with a new operator inside my code?
Thanks
Edit: The method I'm describing in my original answer below is the general way to accomplish DI external of the container. For your specific need - testing - I agree with DJ's answer. It's much more appropriate to use Spring's test support, for example:
#Test
#ContextConfiguration(locations = { "classpath*:**/applicationContext.xml" })
public class MyTest extends AbstractTestNGSpringContextTests {
#Resource
private MyDependency md;
#Test
public void myTest() {
...
While the above example is a TestNG test, there is also Junit support explained in 8.3.7.2. Context management and caching.
General approach: Annotate your class with #Configurable and utilize AspectJ load-time or compile-time weaving. See 6.8.1 in the Spring documentation on AOP for more details.
You can then annotate your instance variables with #Resource or #Autowired. Though they accomplish the same goal of dependency injection, I recommend using #Resource since it's a Java standard rather than Spring-specific.
Lastly, remember to consider using the transient keyword (or #Transient for JPA) if you plan on serializing or persisting the objects in the future. Chances are you don't want to serialize references to your DI'd repository, service, or component beans.
See the autowire() method on the AutowireCapableBeanFactory class. If you use an ClasspathXmlApplicationContext, you can get the factory with getAutowireCapableBeanFactory()
To get the ApplicationContext, you would need to use a static singleton or other central repository, such as JNDI or a Servlet container. See DefaultLocatorFactory on how to get an instance of the ApplicationContext.
If what you need is for testing purposes, Spring has good support for the scenario that you described above.
Check out Spring Reference manual section on Testing