1AOP简介
通知(Advice):通知定义了切面是什么以及何时使用。除了要描述切面要完成的工作,通知还解决了何时执行这个工作的问题。
连接点(Joinpoint):连接点是在程序执行过程中能够插入切面的一个点。这个店可以是方法被调用时、异常被抛出时、甚至字段被编辑时。切面代码可以通过这些点插入到程序的一般流程之中,从而添加新的行为。
切入点(Poincut):切入点可以缩小切面通知的连接点的范围。如果说通知定义了切面的“什么”和“何时”,那么切入点就定义了“何地”。
切面(Aspect):切面是通知和切入点的组合。
引入(Introduction):“引入”允许我们向现有的类添加新方法或者属性。
目标(Target):被通知的对象。
代理(Proxy):是向目标对象应用通知之后被创建的对象。
织入(Weaving):是把切面应用到目标对象来创建新的代理对象的过程。编译时、类加载时、运行时。
主流的Spring:
AspectJ\JBoss AOP\Spring AOP
Spring对AOP的支持:
经典的基于代理的AOP(各版本Spring);
@AspectJ注解驱动的切面。(仅Spring2.0);
纯POJO切面(仅Spring2.0);
注入式AspectJ切面(各版本Spring)。
Spring通知是用Java编写的:
Spring创建的全部通知都是用标准的Java编写的。
Spring在运行时通知对象:
Spring利用代理类包裹切面,从而把他们注入到Spring管理的Bean里。
Spring只支持方法连接点:
由于Spring是基于动态代理的,他只支持方法连接点。
2创建典型的Spring切面
Spring AOP的通知类型:
Before(前):org.springframework.aop.MethodBeforeAdvice
After-returning(返回后):org.springframework.aop.AfterReturningAdvice
After-throwing(抛出后):org.springframework.aop.ThrowsAdvice
Around(包围):org.aopalliance.intercept.MethodInterceptor
Introduction(引入):org.springframework.aop.IntroductionInterceptor
除了Around之外,这些接口都属于Spring。
demo:
通知调用的方法类
定义两种实现方式的通知:
方式1:利用前置、后置、异常通知
方式2:环绕通知
定义切点和通知者:
声明正则表达式切点、联合切点与通知者:
定义AspectJ切点
正则表达式虽然可以作为切点定义语言来使用,但他并不是针对切点而创建的,其主要用途换是文本解析。与之相比,从AspectJ里定义切点的方式就可以看出AspectJ的切点语言是一种真正的切点表达式语言。
使用ProxyFactoryBean:
代理(Proxy):是向目标对象应用通知之后被创建的对象
利用ProxyFactoryBean代理被切面的对象。
调用:
3自动代理
@AspectJ注解
@AspectJ跟AspectJ没有关系。他是Spring用来解析连接点和通知的一组java 5注解。
demo1:
@AspectJ方面详解
切入点声明表达式可以引入别人的表达式如:
@Pointcut("execution(* com.apress.prospring2.ch06.simple.TestBean.*(..))")
private void testBeanExecution() { }
@Around("testBeanExecution()")
public Object log(ProceedingJoinPoint pjp) throws Throwable {
或者
@Around("SystemPointcuts.testBeanExecution()")
public Object log(ProceedingJoinPoint pjp) throws Throwable {
切入点表达式:
execution:匹配方法执行连接点。我们可以指定包、类或者方法名,以及方法的可见性、返回值和参数类型。这是应用的最为广泛的切入点表达式。
within:匹配那些在已声明的类型中执行的连接点。
this:通过用bean引用的类型跟指定的类型做对比来匹配连接点。
args:通过比较方法的参数类型跟指定的参数类型来匹配连接点。
@target:通过检查调用目标对象是否具有特定注解来匹配连接点。
@args:跟args类似,不过@args检查的是方法参数的注解而不是他们的类型。
@within:跟within相似,这个表达式匹配那些带有特定注解的类中执行的连接点。
@annotation:通过检查讲被调用的方法上的注解是否为指定的注解来匹配连接点。
bean:通过比较bean的ID来匹配连接点,我们也可以在bean名模式中使用通配符。
我们可以使用||(或)和&&(与)组合切入点表达式。!(非)取否。
探讨切入点表达式:
1、execution表达式
如:
* com.partner4java..*.*(..)
第一个*表示任意返回类型,..*表示包下的所有类,*(..)表示任意方法和任意参数.
2、within表达式
within(com..TestBean):匹配从TestBean的方法中产生的调用
within(com..*):匹配在com包及其子包的任意类中对任意方法调用的执行过程的切入点。
3、this表达式
this表达式和within表达有些类似,但是不能使用..或者*等通配符。
this(class-name)
4、target表达式
和this完全一样。
5、args表达式
args(type-pattern?(,type-pattern)*)
可以使用..通配符
execution(* SimpleBean.*(String,String))
args(Integer,..,String)
6、@target表达式
4定义纯粹的POJO切面
Spring开发组意识到使用ProxyFactoryBean有些欠优雅,所以致力于提供一种更好的切面声明方式。Spring 2.0里新的XML配置元素就体现出了这种努力。
Spring 2.0的AOP配置元素:
<aop:advisor>:定义一个AOP通知者
<aop:after>:定义一个AOP后通知(不考虑被通知的方法是否成功返回)
<aop:after-returning>:定义一个AOP返回后通知
<aop:after-throwing>:定义一个AOP抛出后通知
<aop:around>:定义一个AOP包围通知
<aop:aspect>:定义一个切面
<aop:before>:顶一个AOP前置通知
<aop:config>:顶级AOP元素。大多数<aop:*>元素必须包含在
<aop:pointcut>:定义一个切点
demo:
使用上面的元素来定义一个完整的切面,其中包含通知者和切入点,不同的是,我们不需要自己声明代理(Proxy)就完成了织入(Weaving)。
调用:
5注入AspectJ切面
虽然Spring AOP对于大多数切面程序来说就足够了,但是与AspectJ相比,他只能算是一个功能较弱的AOP解决方案。AspectJ提供了Spring AOP不可能实现的多种切点类型。
(如果想更深入的了解AspectJ,可以阅读Raminvas Ladded的AspectJ in Action(Manning,2003))
demo:
创建第一个AspectJ方面。
Spring通过添加aspectOf()方法增加对AspectJ的支持,不需要你额外的管理容器。
创建一个aj格式的文件,也就是AspectJ的切面:
配置文件:额外添加factory-method="aspectOf"知名是AspectJ文件
调用:为了让示例程序正常运行,我们必须使用AspectJ编译器(需要像使用JDK那样安装,配置环境变量等)
AspectJ还可以指定“加载时织入”:
使用spring-agent.jar作为JVM代理来替代<aop:aspectj-autoproxy/>,并使用上下文命名空间来初始化加载时织入。
除了ApplicationContext的XML配置文件之外,还需要创建META-INF/aop.xml文件。这个aop.xml文件是一个标准的AspectJ组件。他告诉AspectJ注入器在加载时织入哪些类。
Spring加入<context:load-time-weaver>,可以配置aspectj-weaving,设置on或者off设置开启或关闭织入。
通知(Advice):通知定义了切面是什么以及何时使用。除了要描述切面要完成的工作,通知还解决了何时执行这个工作的问题。
连接点(Joinpoint):连接点是在程序执行过程中能够插入切面的一个点。这个店可以是方法被调用时、异常被抛出时、甚至字段被编辑时。切面代码可以通过这些点插入到程序的一般流程之中,从而添加新的行为。
切入点(Poincut):切入点可以缩小切面通知的连接点的范围。如果说通知定义了切面的“什么”和“何时”,那么切入点就定义了“何地”。
切面(Aspect):切面是通知和切入点的组合。
引入(Introduction):“引入”允许我们向现有的类添加新方法或者属性。
目标(Target):被通知的对象。
代理(Proxy):是向目标对象应用通知之后被创建的对象。
织入(Weaving):是把切面应用到目标对象来创建新的代理对象的过程。编译时、类加载时、运行时。
主流的Spring:
AspectJ\JBoss AOP\Spring AOP
Spring对AOP的支持:
经典的基于代理的AOP(各版本Spring);
@AspectJ注解驱动的切面。(仅Spring2.0);
纯POJO切面(仅Spring2.0);
注入式AspectJ切面(各版本Spring)。
Spring通知是用Java编写的:
Spring创建的全部通知都是用标准的Java编写的。
Spring在运行时通知对象:
Spring利用代理类包裹切面,从而把他们注入到Spring管理的Bean里。
Spring只支持方法连接点:
由于Spring是基于动态代理的,他只支持方法连接点。
2创建典型的Spring切面
Spring AOP的通知类型:
Before(前):org.springframework.aop.MethodBeforeAdvice
After-returning(返回后):org.springframework.aop.AfterReturningAdvice
After-throwing(抛出后):org.springframework.aop.ThrowsAdvice
Around(包围):org.aopalliance.intercept.MethodInterceptor
Introduction(引入):org.springframework.aop.IntroductionInterceptor
除了Around之外,这些接口都属于Spring。
demo:
通知调用的方法类
- packagecn.partner4java.springidol;
- /**
- * 观众需要做的动作
- * (就是当调用演唱的时候,把这些动作顺序的加入到演唱的前后)
- * @author partner4java
- *
- */
- publicclassAudience {
- publicvoidtakeSeats(){
- System.out.println("The audience is taking their seats.");
- }
- publicvoidappluad(){
- System.out.println("CLAP CLAP!");
- }
- publicvoiddemandRefund(){
- System.out.println("Boo! We want our moeny back!");
- }
- }
定义两种实现方式的通知:
方式1:利用前置、后置、异常通知
- packagecn.partner4java.springidol;
- importjava.lang.reflect.Method;
- importorg.springframework.aop.AfterReturningAdvice;
- importorg.springframework.aop.MethodBeforeAdvice;
- importorg.springframework.aop.ThrowsAdvice;
- /**
- * Audience 的通知
- * 利用前置、后置、异常通知
- * @author partner4java
- *
- */
- publicclassAudienceAdviceimplementsMethodBeforeAdvice,
- AfterReturningAdvice, ThrowsAdvice {
- privateAudience audience;
- publicvoidsetAudience(Audience audience) {
- this.audience = audience;
- }
- publicvoidbefore(Method method, Object[] args, Object target)
- throwsThrowable {
- audience.takeSeats();
- }
- publicvoidafterReturning(Object returnValue, Method method,
- Object[] args, Object target)throwsThrowable {
- audience.appluad();
- }
- //There are not any methods on this interface, as methods are invoked by reflection.
- publicvoidafterThrowing(Throwable throwable){
- audience.demandRefund();
- }
- }
方式2:环绕通知
- packagecn.partner4java.springidol;
- importorg.aopalliance.intercept.MethodInterceptor;
- importorg.aopalliance.intercept.MethodInvocation;
- /**
- * Audience 的环绕通知
- * @author partner4java
- *
- */
- publicclassAudienceAroundAdviceimplementsMethodInterceptor {
- privateAudience audience;
- publicvoidsetAudience(Audience audience) {
- this.audience = audience;
- }
- publicObject invoke(MethodInvocation invocation)throwsThrowable {
- try{
- audience.takeSeats();
- Object returnValue = invocation.proceed();
- audience.appluad();
- returnreturnValue;
- }catch(Exception e) {
- audience.demandRefund();
- throwe;
- }
- }
- }
定义切点和通知者:
声明正则表达式切点、联合切点与通知者:
- <?xml version="1.0"encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:aop="http://www.springframework.org/schema/aop"
- xsi:schemaLocation="
- http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans.xsd
- http://www.springframework.org/schema/aop
- http://www.springframework.org/schema/aop/spring-aop.xsd">
- <bean id="audience"class="cn.partner4java.springidol.Audience"/>
- <!-- 通知(Advice):通知定义了切面是什么以及何时使用 -->
- <bean id="advice1"class="cn.partner4java.springidol.AudienceAdvice">
- <property name="audience"ref="audience"></property>
- </bean>
- <bean id="advice2"class="cn.partner4java.springidol.AudienceAroundAdvice">
- <property name="audience"ref="audience"></property>
- </bean>
- <!-- 切入点(Poincut):切入点可以缩小切面通知的连接点的范围 -->
- <bean id="performancePointcut1"class="org.springframework.aop.support.JdkRegexpMethodPointcut">
- <property name="pattern"value=".*perform"></property>
- </bean>
- <!-- 定义AspectJ方式切点 -->
- <bean id="performancePointcut2"class="org.springframework.aop.aspectj.AspectJExpressionPointcut">
- <property name="expression"value="execution(* Performer+.perform(..))"></property>
- </bean>
- <!-- 切面(Aspect):切面是通知和切入点的组合(通知者)-->
- <bean id="audienceAdvisor1"class="org.springframework.aop.support.DefaultPointcutAdvisor">
- <property name="advice"ref="advice1"></property>
- <property name="pointcut"ref="performancePointcut1"></property>
- </bean>
- <bean id="audienceAdvisor2"class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
- <property name="advice"ref="advice1"></property>
- <property name="pattern"value=".*perform"></property>
- </bean>
- <bean id="performer"class="cn.partner4java.springidol.PerformerBean"></bean>
- </beans>
定义AspectJ切点
正则表达式虽然可以作为切点定义语言来使用,但他并不是针对切点而创建的,其主要用途换是文本解析。与之相比,从AspectJ里定义切点的方式就可以看出AspectJ的切点语言是一种真正的切点表达式语言。
使用ProxyFactoryBean:
代理(Proxy):是向目标对象应用通知之后被创建的对象
利用ProxyFactoryBean代理被切面的对象。
- <?xml version="1.0"encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:aop="http://www.springframework.org/schema/aop"
- xsi:schemaLocation="
- http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans.xsd
- http://www.springframework.org/schema/aop
- http://www.springframework.org/schema/aop/spring-aop.xsd">
- <bean id="audience"class="cn.partner4java.springidol.Audience"/>
- <!-- 通知(Advice):通知定义了切面是什么以及何时使用 -->
- <bean id="advice1"class="cn.partner4java.springidol.AudienceAdvice">
- <property name="audience"ref="audience"></property>
- </bean>
- <bean id="advice2"class="cn.partner4java.springidol.AudienceAroundAdvice">
- <property name="audience"ref="audience"></property>
- </bean>
- <!-- 切入点(Poincut):切入点可以缩小切面通知的连接点的范围 -->
- <bean id="performancePointcut1"class="org.springframework.aop.support.JdkRegexpMethodPointcut">
- <property name="pattern"value=".*perform"></property>
- </bean>
- <!-- 定义AspectJ方式切点 -->
- <bean id="performancePointcut2"class="org.springframework.aop.aspectj.AspectJExpressionPointcut">
- <property name="expression"value="execution(* Performer+.perform(..))"></property>
- </bean>
- <!-- 切面(Aspect):切面是通知和切入点的组合(通知者)-->
- <bean id="audienceAdvisor1"class="org.springframework.aop.support.DefaultPointcutAdvisor">
- <property name="advice"ref="advice1"></property>
- <property name="pointcut"ref="performancePointcut1"></property>
- </bean>
- <bean id="audienceAdvisor2"class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
- <property name="advice"ref="advice1"></property>
- <property name="pattern"value=".*perform"></property>
- </bean>
- <!-- 使用ProxyFactoryBean -->
- <bean id="performer"class="cn.partner4java.springidol.PerformerBean"></bean>
- <bean id="duke"class="org.springframework.aop.framework.ProxyFactoryBean">
- <property name="target"ref="performer"></property>
- <property name="interceptorNames"value="audienceAdvisor1"></property>
- <property name="proxyInterfaces"value="cn.partner4java.springidol.Performer"></property>
- </bean>
- </beans>
调用:
- packagecn.partner4java.springidol;
- importorg.springframework.context.ApplicationContext;
- importorg.springframework.context.support.ClassPathXmlApplicationContext;
- publicclassHelloWorld {
- publicstaticvoidmain(String[] args) {
- ApplicationContext ctx =newClassPathXmlApplicationContext(
- "/META-INF/spring/springido.xml");
- Performer performer = (Performer) ctx.getBean("duke");
- performer.perform();
- }
- }
3自动代理
@AspectJ注解
@AspectJ跟AspectJ没有关系。他是Spring用来解析连接点和通知的一组java 5注解。
demo1:
- packagecn.partner4java.spring.aspectj;
- importorg.aspectj.lang.ProceedingJoinPoint;
- importorg.aspectj.lang.annotation.Around;
- importorg.aspectj.lang.annotation.Aspect;
- /**
- * 通过@Aspect注解实现日志记录
- * @author partner4java
- *
- */
- @Aspect
- publicclassLoggingAspect {
- @Around("execution(* cn.partner4java.spring.aspectj.*.*(..))")
- publicObject log(ProceedingJoinPoint joinPoint)throwsThrowable {
- System.out.println("begin");
- Object ret = joinPoint.proceed();
- System.out.println("after");
- returnret;
- }
- }
- packagecn.partner4java.spring.aspectj;
- /**
- * 被测试的bean
- * @author partner4java
- *
- */
- publicclassTestBean {
- publicvoidwork() {
- System.out.println("work");
- }
- publicvoidstop() {
- System.out.println("stop");
- }
- }
- <?xml version="1.0"encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:aop="http://www.springframework.org/schema/aop"
- xsi:schemaLocation="
- http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans.xsd
- http://www.springframework.org/schema/aop
- http://www.springframework.org/schema/aop/spring-aop.xsd">
- <bean id="test"class="cn.partner4java.spring.aspectj.TestBean"/>
- <beanclass="cn.partner4java.spring.aspectj.LoggingAspect">
- </bean>
- <aop:aspectj-autoproxy />
- </beans>
- packagecn.partner4java.spring.aspectj;
- importorg.springframework.context.ApplicationContext;
- importorg.springframework.context.support.ClassPathXmlApplicationContext;
- publicclassLoggingAspectDemo {
- publicstaticvoidmain(String[] args) {
- ApplicationContext ac =newClassPathXmlApplicationContext(
- "/META-INF/spring/ataspectjdemo1-context.xml"
- );
- TestBean testBean = (TestBean) ac.getBean("test");
- testBean.work();
- testBean.stop();
- //后台打印:
- //begin
- //work
- //after
- //begin
- //stop
- //after
- }
- }
@AspectJ方面详解
切入点声明表达式可以引入别人的表达式如:
@Pointcut("execution(* com.apress.prospring2.ch06.simple.TestBean.*(..))")
private void testBeanExecution() { }
@Around("testBeanExecution()")
public Object log(ProceedingJoinPoint pjp) throws Throwable {
或者
@Around("SystemPointcuts.testBeanExecution()")
public Object log(ProceedingJoinPoint pjp) throws Throwable {
切入点表达式:
execution:匹配方法执行连接点。我们可以指定包、类或者方法名,以及方法的可见性、返回值和参数类型。这是应用的最为广泛的切入点表达式。
within:匹配那些在已声明的类型中执行的连接点。
this:通过用bean引用的类型跟指定的类型做对比来匹配连接点。
args:通过比较方法的参数类型跟指定的参数类型来匹配连接点。
@target:通过检查调用目标对象是否具有特定注解来匹配连接点。
@args:跟args类似,不过@args检查的是方法参数的注解而不是他们的类型。
@within:跟within相似,这个表达式匹配那些带有特定注解的类中执行的连接点。
@annotation:通过检查讲被调用的方法上的注解是否为指定的注解来匹配连接点。
bean:通过比较bean的ID来匹配连接点,我们也可以在bean名模式中使用通配符。
我们可以使用||(或)和&&(与)组合切入点表达式。!(非)取否。
探讨切入点表达式:
1、execution表达式
如:
* com.partner4java..*.*(..)
第一个*表示任意返回类型,..*表示包下的所有类,*(..)表示任意方法和任意参数.
2、within表达式
within(com..TestBean):匹配从TestBean的方法中产生的调用
within(com..*):匹配在com包及其子包的任意类中对任意方法调用的执行过程的切入点。
3、this表达式
this表达式和within表达有些类似,但是不能使用..或者*等通配符。
this(class-name)
4、target表达式
和this完全一样。
5、args表达式
args(type-pattern?(,type-pattern)*)
可以使用..通配符
execution(* SimpleBean.*(String,String))
args(Integer,..,String)
6、@target表达式
4定义纯粹的POJO切面
Spring开发组意识到使用ProxyFactoryBean有些欠优雅,所以致力于提供一种更好的切面声明方式。Spring 2.0里新的XML配置元素就体现出了这种努力。
Spring 2.0的AOP配置元素:
<aop:advisor>:定义一个AOP通知者
<aop:after>:定义一个AOP后通知(不考虑被通知的方法是否成功返回)
<aop:after-returning>:定义一个AOP返回后通知
<aop:after-throwing>:定义一个AOP抛出后通知
<aop:around>:定义一个AOP包围通知
<aop:aspect>:定义一个切面
<aop:before>:顶一个AOP前置通知
<aop:config>:顶级AOP元素。大多数<aop:*>元素必须包含在
<aop:pointcut>:定义一个切点
demo:
使用上面的元素来定义一个完整的切面,其中包含通知者和切入点,不同的是,我们不需要自己声明代理(Proxy)就完成了织入(Weaving)。
- <?xml version="1.0"encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:aop="http://www.springframework.org/schema/aop"
- xsi:schemaLocation="
- http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans.xsd
- http://www.springframework.org/schema/aop
- http://www.springframework.org/schema/aop/spring-aop.xsd">
- <bean id="audience"class="cn.partner4java.springidol.Audience"/>
- <bean id="performer"class="cn.partner4java.springidol.PerformerBean"></bean>
- <aop:config>
- <aop:aspect ref="audience">
- <aop:pointcut expression="execution(* *.perform*(..))"id="performance"/>
- <aop:before method="takeSeats"pointcut-ref="performance"/>
- <aop:after-returning method="appluad"pointcut-ref="performance"/>
- <aop:after-throwing method="demandRefund"pointcut-ref="performance"/>
- </aop:aspect>
- </aop:config>
- </beans>
调用:
- ApplicationContext ctx =newClassPathXmlApplicationContext(
- "/META-INF/spring/spring-pojo1.xml");
- Performer performer = (Performer) ctx.getBean("performer");
- performer.perform();
5注入AspectJ切面
虽然Spring AOP对于大多数切面程序来说就足够了,但是与AspectJ相比,他只能算是一个功能较弱的AOP解决方案。AspectJ提供了Spring AOP不可能实现的多种切点类型。
(如果想更深入的了解AspectJ,可以阅读Raminvas Ladded的AspectJ in Action(Manning,2003))
demo:
创建第一个AspectJ方面。
Spring通过添加aspectOf()方法增加对AspectJ的支持,不需要你额外的管理容器。
创建一个aj格式的文件,也就是AspectJ的切面:
- packagecn.partner4java.aspectj;
- publicaspect StockServiceAspect {
- privateString suffix;
- privateString prefix;
- publicvoidsetPrefix(String prefix) {
- this.prefix = prefix;
- }
- publicvoidsetSuffix(String suffix) {
- this.suffix = suffix;
- }
- pointcut doServiceCall() :
- execution(* cn.partner4java.aspectj.*.*(..));
- before() : doServiceCall() {
- System.out.println(this.prefix);
- }
- after() : doServiceCall() {
- System.out.println(this.suffix);
- }
- }
配置文件:额外添加factory-method="aspectOf"知名是AspectJ文件
- <?xml version="1.0"encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="
- http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans.xsd">
- <bean id="stockService"class="cn.partner4java.aspectj.DefaultStockService"/>
- <!-- 额外添加factory-method="aspectOf"知名是AspectJ文件 -->
- <beanclass="cn.partner4java.aspectj.StockServiceAspect"
- factory-method="aspectOf">
- <property name="prefix"value="Before call"/>
- <property name="suffix"value="After call"/>
- </bean>
- </beans>
调用:为了让示例程序正常运行,我们必须使用AspectJ编译器(需要像使用JDK那样安装,配置环境变量等)
- packagecn.partner4java.aspectj;
- importorg.springframework.context.ApplicationContext;
- importorg.springframework.context.support.ClassPathXmlApplicationContext;
- publicclassHelloWorld {
- publicstaticvoidmain(String[] args) {
- //为了让示例程序正常运行,我们必须使用AspectJ编译器
- ApplicationContext ac =newClassPathXmlApplicationContext(
- "/META-INF/spring/aspectjdemo1-context.xml"
- );
- StockService stockService = (StockService) ac.getBean("stockService");
- System.out.println(stockService.getStockLevel("ABC"));
- }
- }
AspectJ还可以指定“加载时织入”:
使用spring-agent.jar作为JVM代理来替代<aop:aspectj-autoproxy/>,并使用上下文命名空间来初始化加载时织入。
除了ApplicationContext的XML配置文件之外,还需要创建META-INF/aop.xml文件。这个aop.xml文件是一个标准的AspectJ组件。他告诉AspectJ注入器在加载时织入哪些类。
Spring加入<context:load-time-weaver>,可以配置aspectj-weaving,设置on或者off设置开启或关闭织入。