2.3、spring+aspectj
Spring在集成了aspectj后,同时也保留了以上的切面与代理的配置方式。
将Spring与aspectj集成与直接使用aspectj不同,不需要定义Aspectj类(它扩展了Java语法的一种新语言,还需要特定的编译器),只需要使用Aspectj切点表达式即可。
1、Spring + Aspectj(基于注解:通过Aspectj execution表达式拦截方法)
增加GreetingAspect类
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
其中包含了环绕增强
该类中的@Aspect注解,表明该类是一个Aspect,其实就是Advisor。该类无需实现任何的接口,只需定义一个方法(名称无所谓),在方法上标注Around注解即可,在注解中使用Aspectj切点表达式。方法的参数中包含一个ProceedingJoinPoint对象,他在aop中称为joinpoint(连接点),可以通过该对象获取方法的任何信息。
切点表达式分析,execution(* com.lhx.chapter4.aop.GreetingImpl.*(..))
execution()标示拦截方法,括号中需要定义匹配的规则
第一个“*”表示方法的返回值是任意的
第二个“*”表示匹配该类中的所有方法
(..)表示方法的参数是任意的
配置Spring的xml
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
proxy-target-class,默认是false,只能代理接口,默认使用JDK代理,true时,代理目标类,使用CGLib代理。
client调用
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
2、Spring + Aspectj(基于注解:通过Aspectj @annotation 表达式拦截方法)
为拦截指定的注解的方法,需要先自定义一个注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Tag {
}
以上定义了一个注解,此注解可标注在方法上,在运行时生效。
Greeting的Aspect类
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
使用了@annotation()表达式,只需要在括号内定义需要拦截的注解名称即可。
直接将Tag注解定义在想要拦截的方法上即可。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
client调试
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
当然也需要使用上一个的xml文件
相关注解说明
Before--前置增强
After--后置增强
Aroung--环绕增强
AfterThrowing--抛出增强
DeclareParents--引入增强
AfterReturning--返回后增强,即finall增强,相当于finally语句,方法结束后执行,比After还要晚一些。
3、Spring + Aspectj:引入增强
定义一个引入增强类
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package com.lhx.chapter4.aop.aopaspectjdeclare; import com.lhx.chapter4.aop.springaopintroductionadvice.Apology; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.DeclareParents; import org.springframework.stereotype.Component; @Aspect @Component public class GreetingAspectDeclare { @DeclareParents(value = "com.lhx.chapter4.aop.GreetingImpl",defaultImpl = ApologyImpl.class) private Apology apology; }
在Aspect类中定义一个需要引用增强的接口,它也就是运行时需要动态实现的接口,在这个接口上标注@DeclareParents注解,注解属性有,
value--目标类,defaultImpl--引入接口的默认实现类。
对引入接口提供实现
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package com.lhx.chapter4.aop.aopaspectjdeclare; import com.lhx.chapter4.aop.springaopintroductionadvice.Apology; public class ApologyImpl implements Apology { @Override public void saySorry(String name) { System.out.println("Sorry " + name); } }
spring的xml配置
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<?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:context="http://www.springframework.org/schema/context" 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/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!--扫描指定包(将带有Compontent注解的类自动定义为Spring bean)--> <context:component-scan base-package="com.lhx.chapter4.aop"></context:component-scan> <aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy> </beans>
客户端校验
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package com.lhx.chapter4.aop.aopaspectjdeclare;
import com.lhx.chapter4.aop.Greeting;
import com.lhx.chapter4.aop.springaopintroductionadvice.Apology;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Client {
public static void main(String[] args) {
//获取spring content
ApplicationContext context =new ClassPathXmlApplicationContext("application-aop-declare.xml");
//从Content中根据id获取Bean对象,其实就是一个代理
Greeting greetingProxy = (Greeting) context.getBean("greetingImpl");
greetingProxy.sayHelloNoPreSub("muzixu ");
Apology apology = (Apology) greetingProxy;
//将目标类强制向上转型为Apology接口类型【引入增强的特性,即“动态接口实现”功能】
apology.saySorry("Jack");
}
}
4、Spring + Aspectj:基于配置
除了使用aspectj注解来定义切面外,Spring AOP也提供了基于配置的方式来定义切面类
配置
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<?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:context="http://www.springframework.org/schema/context" 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/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <bean id="greetingImpl" class="com.lhx.chapter4.aop.GreetingImpl"></bean> <bean id="greetingAspect" class="com.lhx.chapter4.aop.aopaspectj.GreetingAspect"></bean> <aop:config> <aop:aspect ref="greetingAspect"> <aop:around method="around" pointcut="execution(* com.lhx.chapter4.aop.GreetingImpl.*(..))"/> </aop:aspect> </aop:config> </beans>
client使用
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package com.lhx.chapter4.aop.aopaspectjconfig; import com.lhx.chapter4.aop.Greeting; import com.lhx.chapter4.aop.springaopintroductionadvice.Apology; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Client { public static void main(String[] args) { //获取spring content ApplicationContext context =new ClassPathXmlApplicationContext("application-aop-config.xml"); //从Content中根据id获取Bean对象,其实就是一个代理 Greeting greetingProxy = (Greeting) context.getBean("greetingImpl"); greetingProxy.sayHelloNoPreSub("muzixu "); } }
三、aop总结
1、思维导图