https://dev.c-ware.de/confluence/pages/viewpage.action?pageId=7471106
Spring is easy ... AspectJ is easy ... putting them together should be easy too, but there are quite some pitfalls. On this page I will try to doucment some problems I was having in my Projects.
Spring doesn't need AspectJ to work. Everything works great without it. The actual bean-weaving is relatively straight forward. It starts getting interesting as soon as you start using JPA and Transactions.
As soon as you annotate a method with "@Transactional" Spring has to make sure that a Transaction is created. But how can this be done? Lets think of Bean A calling a method called "doTheBThing" on a Bean B. If "doTheBThing" is marked Transactional, then Somehow a transaction has to be created before executing the method and it has to be committed/rolled-back after it finishes.
The solution is not to give A a real reference to B but to give it a reference to an Object that has the same Interface and which wraps the Transactional code around the real call to B.
Depending on your case there are two basic approaches:
Dynamic-Proxies: In this case you have to have an Interface describing the Interface of your bean since the Proxy class is only able to create an Object based upon an Interface. (http://www.roseindia.net/javatutorials/dynamic_proxies_tutorial.shtml)
CGLib: This approach needs no Interface as it dynamically creates a Class extending the original Class which wraps the transactional Code around the actual call to super.doTheBThing.
I found a good comparison of the two approaches on this page: http://insufficientinformation.blogspot.com/2007/12/spring-dynamic-proxies-vs-cglib-proxies.html
Your system will propably work with the spring defaults ... as long as you dont't want to use AspectJ for creating some of your own Aspects.
For Example I created a SecurityChecker Aspect that should secure calls to specially annotated Classes and Methods. This is where I really got into trouble using Dynamic Proxies. As the Proxy implements an Interface without keeping the annotations, it was allmost impossible for me to access the annotation information. Using CGLib all I had to do, was to access the genericSuperClass property and I could read all my Annotations. Another rather anoying thing is that I sort of like to stick to one concept and having mixed Dynamic Proxies and CGLib Proxies sort of disturbed my asthetic impression of the software.
Weaving types
AspectJ weaving can be done in three fashions:
- Compile-Time-Weaving, which does the weaving during the compilation of the classes
- Post-Compile-Time-Weaving, which sort of modifies allredy compiled classes and outputs modified versions of class files
- Load-Time-Weaving, which does the weaving while loading the classes in the classloader
The last option it the one I'm going to be talking about.
Configuring Load-Time-Weaving (LTW)
In order to utilize the Load-Time-Weaving (LTW) we have to influence the way classes are loaded. This can generally be done in two fashions:
- Using an "agent"
- Exchanging the classloader
Using an "agent"
Well I have to admit that I haven't really figgured out what exactly the agents do. All I know it that specifying a LTW-agent makes the entire Java VM become AspectJ-aware. Not by exchanging the classloader but some different means. I have to admit, that at the curent point I don't really care how they do it, as long as they do it.
The agent is configured by adding a
in my current maven-based environment this would be
which has to be added to the java commandline together with all the other Xmx- and Xms-settings.
Exchanging the classloader
As mentioned in the agent-section, specifying an agent changes the entire Java VM. So what if for example you want to enable LTW for one application of an application-server or servlet-engine? In this case we have to go the classloader-way. I'll explain this for tomcat.
At first tomcat has to be provided with the custom classloader. For this the spring-tomcat-weaver.jar (in my case spring-tomcat-weaver-2.5.6.SEC1.jar) has to be placed in the tomcat lib-directory. The second step, is to configure the classloader for the contexts you want to user LTW in. This is done by placing the following file with the name context.xml in the Web-applications META-INF directory:
This turns on LTW for only this context.
What happens during startup?
So now it's getting interesting. So as soon as you startup your application with one of the two approaches described above and a class is loaded, the load-time-weaver looks through the classpath for META-INF/aop.xml files. Here comes an example of one of my aop.xml fiels:
Yeah ... I know what you're thinking "not a profiler aspect again!" but mine is cooler as 90% of the rest
Now let's have a look at the file, the first part "weaver" tells the weaver to include the "de" package and all of it's sub-packages (did you notice the double "."?) If you only want to weave one package and not it's sub-packages, just use one period.
In the second part "aspects" the Aspect classes are listed. So even if you might have thousands of Apects in your jar-files, only the ones listed here will be woven.
Now I mentioned that my profiler is cooler than most of the hellow-aspect-world-profilers, so what makes it so cool? ... well it doesn't log to the console, but to a database using spring and jpa.
Here comes the code:
So why is this so cool? ... well I have to admit it isn't but if you try to do this using 90% of the tutorials available in the web you will certainly fail and you'll be stuck for quite a while (as I was). So now lets dig into the problem:
A spring aspect is woven using the META-INF/aop.xml and is configured by a spring config-file. Unfortunately allmost all Spring+AspectJ examples are missing one vital part ... the Spring beans never get dependencies injected as they all use Log4j or the console to output their profiling information. Following the tutorials, I created a aop.xml to configure the weaving and a Spring config-file to configure my Aspect. When starting the application I could see that the Apect was woven as expected. Unfortunately when executing the Aspect logic, I got tons of NullPointerExceptions. When you have to debug Aspect woven code you will relatively soon start cursing ... I ended up adding System.out.prinln statemnts all over my code. When having a deeper look I could see that at the beginning two instances were created. The setJpaTemplate was called for the second instance and all calls to the Aspect logic were called on the first instance ... so why was this so?
After quite some searching, I stumbled over this page http://www.ibm.com/developerworks/java/library/j-aopwork13.html. This was the first time I read a post in which somebody actually did dependency-injection. In this article there was one sentance that cleared up the picture for me: "For the most common case of singleton aspects such as the RemoteExceptionHandling aspect above, AspectJ defines an aspectOf() method that returns the aspect instance."
So that was the reason! AspectJ created one instance and wove this in the code. Then, when configuring the Spring context, another instance was created and that was configured correctly with the jpaTemplate. Using the information of the IBM article I found out that simply changing the spring config from:
to:
made spring call the public static "aspectOf" method to get a reference to the allready instanciated Aspect instance and to configure that one instead.
Now if you are using IntelliJ or some similarly intelligent IDE it will certainly complain about no "aspectOf"-method being available ... trust me, If you setup your weaving correctly, it will exist.
Just because none of the oher articles ever described this mystical "aspectOf"-Method, I waseted about two full days. This was why I thought I should write this down and mabe it helps someone else save a day or two
相关推荐
spring+aspectjweaver-1.7.1.jar+aspectj-1.8.9.jar+aopalliance.jar
以公司订单管理的模型为例(大部分步骤和业务了逻辑已经删除,只保存AOP注解这一部分)Spring AOP
NULL 博文链接:https://tuoxinquyu.iteye.com/blog/1465187
官网最新 aspectjweaver.jar+aspectjrt.jar+aspectj-1.8.9-src.jar
NULL 博文链接:https://tuoxinquyu.iteye.com/blog/1465155
本书以AOP基础理论为主线,首先讲解AOP的产生与发展、为什么要应用AOP、AOP的核心概念,然后详细讲解AspectWerkz、AspectJ、Spring框架的AOP应用开发技术。 随书附赠的光盘内容为本书开发的案例程序包。本书内容循序...
本书以AOP基础理论为主线,首先讲解AOP的产生与发展、为什么要应用AOP、AOP的核心概念,然后详细讲解AspectWerkz、AspectJ、Spring框架的AOP应用开发技术。 随书附赠的光盘内容为本书开发的案例程序包。本书内容循序...
1: 分析解释静态代理框架 AspectJ演变过程 2:增加AspectJ案例 3:分析AspectJ字节码
7. // 如果不用此包,在启动时抛 出:nested exception is java.lang.NoClassDefFoundError: org/aspectj /weaver /reflect/ReflectionWorld$ReflectionWorldException 8. aspectjweaver.jar 9. 10. //如果不用此...
Android Realm数据库配合aop框架封装
Spring 使用AspectJ 实现 AOP之前置通知小例子,实际跑过,验证可信。
spring aspectj aspectrt.jar
Spring 使用AspectJ 实现 AOP(基于xml文件、基于注解)
spring通过aspectj来实现事务控制
spring和aspectj的aop实验,详细内容可以移步至博客:https://mp.csdn.net/postedit/97750888
Spring AOP的AspectJ支持jar包; 包括: com.springsource.net.sf.cglib-2.2.0.jar com.srpingsource.org.aopalliance-1.0.0.jar com.srpingsource.org.aspectj.weaver-1.68.RELEASE.jar
第7章:对如何使用基于AspectJ配置AOP的知识进行了深入的分析,这包括使用XML Schema配置文件、使用注解进行配置等内容。 第8章:介绍了Spring所提供的DAO封装层,这包括Spring DAO的异常体系、数据访问模板等...
JavaEE AspectJ基于注解的配置
第7章:对如何使用基于AspectJ配置AOP的知识进行了深入的分析,这包括使用XML Schema配置文件、使用注解进行配置等内容。 第8章:介绍了Spring所提供的DAO封装层,这包括Spring DAO的异常体系、数据访问模板等...
Spring spectJ AOP 前置通知 后置通知 返回通知 异常通知 环绕通知