Spring整合aspectj框架实现的aop
在现在的开发中使用这种方案比较多.
在spring2.0以后它支持jdk1.5注解,而整合aspectj后可以使用aspectj语法,可以简化开发。
Aspect:切面 =切点+通知(多个切点与多个通知的组合)
AspectJ它是一个第三方框架,spring从2.0后可以使用aspectJ框架的部分语法.
AspectJ框架它定义的通知类型有6种
1. 前置通知Before相当于BeforeAdvice
2. 后置通知AfterReturning相当于AfterReturningAdvice
3. 环绕通知 Around 相当于MethodInterceptor
4. 抛出通知AfterThrowing相当于ThrowAdvice
5. 引介通知DeclareParents相当于IntroductionInterceptor
6. 最终通知After不管是否异常,该通知都会执行
相比spring的传统AOP Advice多了一个最终通知
第一步:创建目标(target)
public class UserServiceImpl implements UserService {
@Override
public int add() {
int a = 10 / 0;
System.out.println("add......");
return 66;
}
@Override
public void del() {
System.out.println("del......");
}
@Override
public void update() {
System.out.println("update......");
}
@Override
public void find() {
System.out.println("find......");
}
}
public class UserServiceImpl implements UserService {
@Override
public int add() {
int a = 10 / 0;
System.out.println("add......");
return 66;
}
@Override
public void del() {
System.out.println("del......");
}
@Override
public void update() {
System.out.println("update......");
}
@Override
public void find() {
System.out.println("find......");
}
}
第二步:创建通知(增强 advice)
注意:在aspectj中它的增强可以不实现任何接口,只需要定义出增强功能(方法)
//advice
public class UserServiceHelper{
//前置通知+参数
public void before(JoinPoint jp){
System.out.println("拦截的目标类" + jp.getSignature().getDeclaringTypeName());
System.out.println("拦截的方法" + jp.getSignature().getName());
System.out.println("前置......");
}
//后置通知
public void after(JoinPoint jp , Object val){
System.out.println("返回值为" + val);
System.out.println("后置.....");
}
//环绕通知
public Object around(ProceedingJoinPoint pip) throws Throwable{
System.out.println("环绕前");
Object proceed = pip.proceed();
System.out.println("环绕后");
return proceed;
}
//异常抛出通知
public void afterThrowing(JoinPoint jp,Throwable ex){
System.out.println(ex);
System.out.println("发现异常");
}
//最终通知
public void end(JoinPoint jp){
System.out.println(jp.getSignature().getName());
System.out.println("结束");
}
第三步:在spring的xml配置文件中来配置
<aop:config>下的<aop:aspect>是aspectJ框架用来声明切面的。
applicationContext.xml配置文件
<aop:config>
<aop:aspect ref="userServiceAdvice">
<aop:pointcut expression="execution(* com.itheima.aspectj.* .*(..))" id="myPointCut"/>
<aop:before method="before" pointcut-ref="myPointCut" /> 前置
<aop:after-returning method="after" pointcut-ref="myPointCut" /> 后置
<aop:around method="around" pointcut-ref="myPointCut"/> 环绕
<aop:after-throwing method="afterThrowing" pointcut-ref="myPointCut"/> 发现异常
<aop:after method="end" pointcut-ref="myPointCut"/> 最终
</aop:aspect>
</aop:config>
//前置通知
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class AspectjTest {
@Autowired
private UserService userService;
@Test
public void test(){
userService.del();
}
public class UserServiceHelper {
//前置通知+参数
public void before(JoinPoint jp){
System.out.println("拦截的目标类" + jp.getSignature().getDeclaringTypeName());
System.out.println("拦截的方法" + jp.getSignature().getName());
System.out.println("前置......");
}
//后置通知
public void after(JoinPoint jp , Object val){
System.out.println("返回值为" + val);
System.out.println("后置.....");
}
//环绕通知
public Object around(ProceedingJoinPoint pip) throws Throwable{
System.out.println("环绕前");
Object proceed = pip.proceed();
System.out.println("环绕后");
return proceed;
}
//异常抛出通知
public void afterThrowing(JoinPoint jp,Throwable ex){
System.out.println(ex);
System.out.println("发现异常");
}
//最终通知
public void end(JoinPoint jp){
System.out.println(jp.getSignature().getName());
System.out.println("结束");
}
<aop:config>
<aop:aspect ref="userServiceAdvice">
<aop:pointcut expression="execution(* com.itheima.aspectj.* .*(..))" id="myPointCut"/>
<aop:before method="before" pointcut-ref="myPointCut" /> 前置
<aop:after-returning method="after" pointcut-ref="myPointCut" returning="val" /> 后置
<aop:around method="around" pointcut-ref="myPointCut"/> 环绕
<aop:after-throwing method="afterThrowing" pointcut-ref="myPointCut" throwing="ex"/> 发现异常
<aop:after method="end" pointcut-ref="myPointCut"/> 最终
</aop:aspect>
</aop:config>
关于代理方式选择
在spring的aop开发中,它使用的是代理方案,代理实现有两种:
1. jdk的proxy
2. cglib
spring框架默认情况下,会对有接口的类使用proxy代理。没有接口的类使用cglib代理
如果为false 那么如果有实现接口 那么为jdk的proxy 没有接口则为cglib
如果为true 那么不管有没有实现接口 默认为cglib
Proxy-target-class的值默认是false,它代表有接口使用proxy代理
问题:如果现在对目标要使用cglib代理(不考虑是否有接口)?
只需要将proxy-target-class设置为true.