Trying to design simple aspect,that will print word "logg" to console,when any of public methods executed.
aspect:
#Aspect
public class LoggingAspect {
#Pointcut("execution(public * *(..))")
public void publicServices() {
};
#Before("publicServices()")
public void logg() {
System.out.println("logg");
}
}
xml config:
<context:component-scan base-package="aspectlogging" />
<aop:aspectj-autoproxy/>
<bean id="loggingAspectHolder" class="aspectlogging.LoggingAspect"/>
simple bean:
package aspectlogging;
#Component
public class TestableBean {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
test:
public class TestLogging {
public static void main(String[] args) {
TestableBean tb = new TestableBean();
tb.setName("yes");
tb.getName();
}
}
I expect,that result of running of TestLogging will be "logg" word in console,and no output returned.
Do I understand AOP correctly in this case?
With #Around advice, you need to have a ProceedingJoinPoint pjp argument to the advising method and to call pjp.proceed() at the point in the advisor when you want the wrapped method to be called. It's easier to use #Before advice really, when what you've done will otherwise work just fine.
[EDIT]: Also, you must let Spring construct your beans for you instead of directly calling new. This is because the bean object is actually a proxy for your real object (which sits inside it). Because your target object doesn't implement an interface, you will need to have the cglib library on your classpath in addition to the Spring libraries. (Alternatively, you can go with using AspectJ fully, but that requires using a different compiler configuration.)
To create your beans, you first need to create a Spring context and then query that for the bean instance. This means you change from:
TestableBean tb = new TestableBean();
To (assuming you're using Spring 3, and that your XML config is in "config.xml" somewhere on your classpath):
ApplicationContext context = new ClassPathXmlApplicationContext("config.xml");
TestableBean tb = context.getBean(TestableBean.class);
The rest of your code remains the same (after adjusting for import statements and possibly additional dependencies).
Not quite sure on this one, but maybe you need to use a spring managed TestableBean to have spring AOP pick up the method call.
edit: of course, you can't use #Around the way that you provided - but this subject has been addressed by another answer, so it's omitted here.
edit2: If you need help on how to get a spring managed bean, please feel free to ask. but since you already got your aspect bean set up, I believe you can handle this :)
edit3: Hehe. Ok.. maybe not :)
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
will load your application context.
Load beans from there by calling:
TestableBean testableBean = (TestableBean )ctx.getBean("testableBean ");
Define the TestableBean just like you did with your Aspect bean.
edit4: Now I'm pretty sure that the fault is the non-spring managed bean.
Use the simplest thing that can work. Spring AOP is simpler than using full AspectJ as there is no requirement to introduce the AspectJ compiler / weaver into your development and build processes. If you only need to advise the execution of operations on Spring beans, then Spring AOP is the right choice. If you need to advise domain objects, or any other object not managed by the Spring container, then you will need to use AspectJ.
Taken from: http://static.springsource.org/spring/docs/2.0.x/reference/aop.html
Related
Spring uses either JDK dynamic proxies or CGLIB to create the proxy for a given target object. If a class is annotated with #Configuration, then CGLIB is used.
However, one limitation of Spring AOP is that once the call has finally reached the target object, any method calls that it may make on itself are going to be invoked against the this reference, and not the proxy. This piece of information is important to remember when using #Transactional and in other places as well.
So having that knowledge, in the code below, is Spring injecting the actual instance or the proxy of SimpleBean?
#Configuration
public class Config {
#Bean
public SimpleBean simpleBean() {
return new SimpleBean();
}
#Bean
public SimpleBeanConsumer simpleBeanConsumer() {
return new SimpleBeanConsumer(simpleBean()); //<---
}
}
And what is the behavior if a class is annotation with #Component?
Let me give you another perspective.
Say there is an another bean AnotherBeanConsumer that also needs a simpleBean. Simple Bean has a Singleton scope:
#Configuration
public class Config {
#Bean
public SimpleBean simpleBean() {
return new SimpleBean();
}
#Bean
public SimpleBeanConsumer simpleBeanConsumer() {
return new SimpleBeanConsumer(simpleBean());
}
#Bean
public AnotherBeanConsumer anotherBeanConsumer() {
return new AnotherBeanConsumer(simpleBean());
}
}
Now the question is, how its possible that two calls to simpleBean() made from different methods simpleBeanConsumer and anotherBeanConsumer return the same instance of the simple bean (since its a singleton obviously)?
IMO (and disclaimer, I'm not affiliated with spring or something), This is the main reason of creating proxies that wrap Configurations.
Now indeed Spring AOP has a limitation of calling methods just as you've stated, however who said that spring under-the-hood uses spring AOP? The bytecode instrumentation done on much lower levels doesn't have a limitation like this. After all creating a proxy means: "create a proxy object that will have the same interface but will alter the behavior", right?
For example if you use CGLIB that uses inheritance you could create a proxy out of configuration that looks like this (schematically):
class CGLIB_GENERATED_PROXY extends Config {
private Map<String, Object> singletonBeans;
public SimpleBean simpleBean() {
String name = getNameFromMethodNameMaybePrecached();
if(singletonBeans.get(name) != null) {
return singletonBeans.get(name);
}
else {
SimpleBean bean = super.simpleBean();
singletonBeans.put(name, bean);
return bean;
}
}
....
}
Of course its only a schematic picture, in real life there is an application context that basically provides the access to the map like this, but you get the point.
If its not enough, then there are some even more sophisticated frameworks that spring must make use of in order to load a configuration (like ASM)...
Here is an example:
If you use #ConditionalOnClass(A.class) and the class doesn't really exist in runtime, how spring can load the bytecode of the configuration that uses this configuration and not fail on something like NoClassDefFoundException?
My point is that it goes far beyond the spring AOP, and has its quirks :)
Having said that, nothing that I've describe above requires the real components to be always wrapped in Proxies of any kind. So in the most trivial case, when SimpleBean does not by itself have some annotations that require proxy generation (stuff like #Cached, #Transactional and so forth), Spring won't wrap the object of that type and you'll get a plain SimpleBean object.
I tried to use PointCut to perform some post action after ModelAndView.setViewName, but it seems that it never triggers:
#Aspect
#Component
public class TestAspect {
private Logger logger = LoggerFactory.getLogger(this.getClass());
#Pointcut("execution(* org.springframework.web.servlet.ModelAndView.*(..))")
public void testPointCut() {
}
#After("testPointCut()")
public void afterPointCut(JoinPoint joinPoint) {
logger.debug("afterPointCut");
}
}
If I change the execution part to some class of my own, this point cut works.
So what is the correct way to add PointCut to ModelAndView?
I am not a Spring user, but what I know about Spring AOP is that you can only apply it to Spring components. The class ModelAndView is not derived from any Spring core component class or annotated by anything making it such, it is a simple POJO. As such you cannot target it by Spring AOP pointcuts. You should rather target something within the reach of Spring AOP.
The alternative would be to unpack the big gun and use full AspectJ LTW (load-time weaving) which is not limited to Spring components.
I have this
#Bean public CommandLineRunner commandLineRunner(ApplicationContext ctx) {
// use a lambda expression to define a CommandLineRunner
return args -> {
... work ...
};
}
which is invoked like this
SpringApplication app = new SpringApplication(MyApp.class);
app.run(args); // perform configuration magic and invoke the above lambda function
This works great as long as the application was only used from the CLI. Now, the application is going through some refactoring to support a new run-time platform, and now I would like to do this:
app.run(complexOject); // pseudo-code, no such method in SpringApplication
i.e. I need to pass an ComplexObject to the application, while still preserving all the magic auto-configuration.
How can this be accomplished? Solutions with the least amount of code change are preferred.
The refactoring steps to enable a CommandLineRunner to receive arbitrary parameters is roughly as follows:
Move the guts (the ... work ... part) of the commandLineRunner method to a new method in a new bean class e.g. #Component public class GenericRunner { public void run(String ... args) ... }.
This is the most important step: Delete the original CommandLineRunner #Bean definition in its entirety. This will cause the application's run() method to exit after performing configuration.
Replace the app.run(args); invocation with the following
ConfigurableApplicationContext ctx = app.run(); // oh yeah
GenericRunner runner = ctx.getBean(GenericRunner.class);
runner.run(args);
Re-run all tests, commit the code changes.
The actual refactoring is now trivial: modify the runner.run(args) call at will. This is just a straight call into the GenericRunner POJO and is free of SpringBoot rules and limitations.
SpringApplication class obviously doesn't have a method that gets this output stream, its an entry point to the complicated by very powerful spring boot application loading process.
If the goal is to store the log of the application consider logging configuration rather than using output streams.
Otherwise please describe the requirement, what is the purpose of this output stream and I'll do my best to update this answer.
Update:
SpringApplication starts up an application context that is used as a registry for spring beans in the application.
So the most "spring friendly solution is to define a ComplexObject to be a spring bean, so that it will be injected into other beans that might need it.
This will work great if this bean can be created during the application startup.
Example:
class ComplexObject {...}
class ServiceThatMaintainsAReferenceOnObject {
private ComplexObject complexObject;
// all arg constructor
}
#Configuration
class SpringConfiguration {
#Bean
public ComplexObject complexObject() {
return new ComplexObject();
}
#Bean
public ServiceThatMaintainsAReferenceOnObject service(ComplexObject complexObject) {
return new ServiceThatMaintainsAReferenceOnObject(complexObject);
}
}
Now, if this complex object has to be created outside the spring application, maybe you need to pass it to some bean method as a parameter, after the application context is created. This can also be a case in the question, although it's definitely not a Spring way to do things.
Here is an example:
class ComplexObject {}
class Service {
void foo(ComplexObject complexObject);
}
#Configuration
class MyConfiguration {
#Bean
public Service service() {
return new Service();
}
}
// inside the main class of the application:
SpringApplication app = ...
ComplexObject complexObject = ... // get the object from somewhere
ApplicationContext ctx = app.run(args);
// by this time, the context is started and ready
Service service = ctx.getBean(Service.class);
service.foo(complexObject); // call the method on bean managed by spring
All in all, usually the second approach is not a regular use case of spring application, although its kind of feels like you're looking for something like this in the question.
All-in-all I think you should learn and understand how Spring works in a nutshell, and what exactly the ApplicationContext is to provide the best solution (I'm sorry for mentioning this, I said so because from the question it looks like you haven't really worked with Spring and don't really understand what does it do and how does it manage the application).
In older Spring MVC apps, where you'd specify application.xml and declare your app's beans so that Spring DI could instantiate them and wire them together, you might have something like this:
<bean id="chargeFactory" class="com.example.myapp.ChargeFactory" />
<bean id="paymentService" class="com.example.myapp.DefaultPaymentService">
<ref id="chargeFactory"/>
</bean>
<bean id="chargeAuditor" class="com.example.myapp.ChargeAuditor">
<ref id="chargeFactory"/>
</bean>
Which might help wire up the following code:
public interface PaymentService {
public void makePayment(Payment payment);
}
public class DefaultPaymentService implements PaymentService {
#Autowired
private ChargeFactory chargeFactory;
#Override
public void makePayment(Payment payment, String key) {
Charge charge = chargeFactory.createCharge(key);
charge.doCharge(payment);
}
}
public class ChargeAuditor {
#Autowired
private ChargeFactory chargeFactory;
public void auditAllCharges(String key) {
List<Charge> charges = chargeFactory.getAllCharges(key);
// blah whatever
}
}
How do you accomplish the same bean wiring in Spring Boot with the #Configuration class? For example:
#Configuration
public class MyAppInjector {
#Bean
public ChargeFactory chargeFactory() {
return new ChargeFactory();
}
#Bean
public PaymentService paymentService() {
return new DefaultPaymentService(chargeFactory());
}
#Bean
public ChargeAuditor chargeAuditor() {
return new ChargeAuditor(chargeFactory());
}
}
This might work but introduces some issues:
It would force me to have to write value constructors for all my classes, which goes against everything I see in literally every tutorial/article I've come across. Plus, if I had to do that, then there's no real value to #Autowired anyways...
At this point I'm essentially doing "DIY DI", which is OK, except I'm trying to deliberately use Spring DI :-)
Every time I call chargeFactory() I'm getting a new (prototype-style) ChargeFactory instance. Maybe I want a singleton. Using this approach I have to hand-roll my own singleton implementation.
Sure, I can do all of this, but I feel like I'm flagrantly misusing/misunderstanding how #Configuration is supposed to be used, because it seems like I'm introducing a whole lot of DIY/homegrown code to solve something Spring DI should be able to do for me.
How would I reference the chargeFactory bean and wire it into both the "provider methods" for the paymentService and chargeAuditor beans? Again, looking for the Java-based #Configuration solution instead of writing an XML document to define the wirings.
I found this article which seems to be the only tutorial/documentation (surprisingly) on wiring Spring Boot apps via #Configuration (which leads me to believe there might be other/better methods...), but it does not address:
How to specify singleton vs prototype bean instantiation patterns
If multiple instances of a bean-class exist, how do I specify which instance gets wired into which dependency?
How do I get around not defining value constructors for all my classes, and just let Spring/#Autowired inject fields automagically?
When you call chargeFactory() , spring won't create new instance everytime. Give it a try and see. Same object will be returned. Anyways
You can do something like this.
#Bean
public PaymentService paymentService(ChargeFactory chargeFactory) { return new DefaultPaymentService(chargeFactory); }
I am currently improving my Spring knowledge. I wonder what really happens when I use Spring annotation #Autowire on a field.
Here is a piece of code :
OutputHelper file
#Component
public class OutputHelper {
#Autowired
#Qualifier("csvOutputGenerator")
private IOutputGenerator outputGenerator;
public void setOutputGenerator(IOutputGenerator outputGenerator) {
this.outputGenerator = outputGenerator;
}
// I can focus only on what my code do because my objects are injected
public void generateOutput(){
outputGenerator.generateOutput();
}
}
CsvOutputGenerator file
#Component
public class CsvOutputGenerator implements IOutputGenerator {
public void generateOutput(){
System.out.println("Csv Output Generator");
}
}
Application file
public static void main(String[] args) {
// Create the spring context
ApplicationContext context = new ClassPathXmlApplicationContext("META-INF/spring/spring-module.xml");
// Get the configured OutpuHelper from the spring-module.xml
OutputHelper output = (OutputHelper) context.getBean("outputHelper");
// Display output from the output configured
output.generateOutput();
}
My configuration file just contain <context:component-scan base-package="com.xxx.xxx.output"/>
When I execute this code all work fine. But what makes me surprised is when I delete the setOutputGenerator in OutPutHelper file, my piece of code keeps working. I tought that with this configuration, the OutputHelper was first created with default constructor and initialized with setter.
I expected an error because the variable outputGenerator was not be able to be initialized.
Is anyone can help me to understand ?
The idea to have fields #Autowired is questionable. It works, but it will difficult other aspects of your implementation (i.e. testing).
There are 3 types of injections:
fields - basically configured applying reflection (Field.set(Object, Object)) directly to the field:
#Autowired
private MyInterface field;
setters - with this approach the configuration of each dependency goes through a property (spring goes through all methods and execute each one annotated with #Autowired using Method.invoke(Object, Object...), thus its value is configured using its setter as follows:
#Autowired
public void setField(MyInterface value) {
this.field = value;
}
constructors - the last, and my preferable approach, the constructor injection. That one basically annotates an constructor with #Autowired and instead of using methods or fields, you can configure your bean directly on your constructor. For that spring will elect the a constructor to be used to instantiate your #Component, and it will use an #Autowired if existent or a empty params constructor, invoking it using Constructor.newInstance(Object...). Example:
#Component
public class Implementation {
private MyInterface field;
#Autowired
public Implementation(MyInterface value) {
Assert.notNull(value, "value should not be null");
this.field = value;
}
}
One of the ideas behind Inversion of Control (or Dependence Injection) is to be able to isolate a piece of code in order to provide decent test implementation support.
In order to go deeper, it is necessary to comment that during a unit test you want the class in its isolated form, all you will use with that class are basically mocks for its dependencies (injections).
So, what are the results:
If you do field injection, it will be quite costly to every single time set the beans using some reflection to configure the bean during your tests (another logic needs to be introduced to configure the bean to be tested).
With setter injection approach you will be able to use your own bean to configure it with mocks necessary to isolate your implementation and test its functionality.
And finally, with the constructor injection approach you will have not only the support to configure your bean, but you will be able to require its dependencies. This means that for every new dependency a new parameter on your constructor is added, this brings you come advantages on development time, for example, you will be able to see on development time the unit tests affected with the introduction of that new dependency (once your IDE will point it out for your).
Simple answer
Actually, the setter is useless, since the CDI use java Reflection to access fields.
It means that fields are no longer accessed by method calls.
Reflection allow iterating throught all fields of a class and check if there are annoted with a specific annotation.
In this case, if a field in your class is annoted With #Autowired (or #Inject wich is more J2E complient), the container will iterate throught searching if there is a registered bean that fits the current property.
Going deeper
When you context is starting, the container iterate classes and search all field annoted with #Inject or #Autowired.
For these fields, it search an available bean.
Here is the must simple example :
public class SpringClassInChargeOfDependencyInjection {
public void handdleInjections(T objectWithInjectableField) {
Class<T> clazz = objectWithInjectableField.class;
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
if (field.isAnnotationPresent(Autowired.class) || field.isAnnotationPresent(Inject.class)) {
//find a bean for the type;
Object injectableBean = getAvailablebean(field.getType());
field.setAccessible(true);
//inject the value into the class, this line explain why the setter is not necessary
field.set(objectWithInjectableField, injectableBean);
}
}
}
}
This is a non-working example just to explain how it works.
Tips
You might consider using #Inject instead of #Autowired, the later was created by Spring, #Inject is a part of the the JSR-330. Spring does understand #Inject as well, you just need to add the javax.inject jar dependency to your project. If later you want to switch from spring to something else (guice for example) you won't have to change all your #Autowired annotations
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>