SpringAOP 架构 与AspectJ 混用---------------常用
使用AspectJ 实现AOP
所依赖的jar包 除spring基本包之外 还应添加
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.3.9.RELEASE</version>
</dependency>
<!-- AOP联盟的API包 -->
<dependency>
<groupId>aopalliance</groupId>
<artifactId>aopalliance</artifactId>
<version>1.0</version>
</dependency>
<!-- aspectJ织入包 -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.9</version>
</dependency>
<!-- spring整合aspectJ -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>4.3.9.RELEASE</version>
</dependency>
工作中基本上是 注解与Xml并存的开发模式
基于AspectJ的注解AOP开发
注解开发:环境准备
<?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">
<!-- 开启AspectJ自动代理-->
<aop:aspectj-autoproxy />
</beans>
@AspectJ提供不同的通知类型(定义切面类)
• @Before 前置通知,相当于BeforeAdvice
• @AfterReturning 后置通知,相当于AfterReturningAdvice
• @Around 环绕通知,相当于MethodInterceptor
• @AfterThrowing异常抛出通知,相当于ThrowAdvice
• @After 最终final通知,不管是否异常,该通知都会执行
• @DeclareParents 引介通知,相当于IntroductionInterceptor (类似于 采用拦截器,不要求掌握)
在通知中通过value属性定义切点
• 通过execution函数,可以定义切点的方法切入
• 语法:
– execution(<访问修饰符>?<返回类型><方法名>(<参数>)<异常>)
匹配所有类public方法
execution(public * *(..))
匹配指定包下所有类方法
execution(* com.imooc.dao.*(..)) 不包含子包
execution(* com.imooc.dao..*(..)) ..*表示包、子孙包下所有类
匹配指定类所有方法
execution(* com.imooc.service.UserService.*(..))
匹配实现特定接口所有类方法
execution(* com.imooc.dao.GenericDAO+.*(..))
匹配所有save开头的方法
execution(* save*(..))
@Before前置通知
可以在方法中传入JoinPoint对象,用来获得切点信息
@Before(value = "execution(* com.yu.demo1.UserDao.add(..))")
public void doBefore(JoinPoint joinPoint) {
System.out.println("----前置通知----" + joinPoint);
}
@AfterReturing 后置通知
通过returning属性 可以定义方法返回值,作为参数
@AfterReturning(value = "execution(* com.yu.demo1.UserDao.deleted(..))", returning = "result")
public void doAfterReturing(Object result) {
System.out.println("----前置通知----" + result);
}
@Around 环绕通知
around方法的返回值就是目标代理方法执行返回值
参数为ProceedingJoinPoint 可以调用拦截目标方法执行
重点:如果不调用 ProceedingJoinPoint的 proceed方法,那么目标方法就被拦截了
@Around(value = "execution(* com.yu.demo1.UserDao.update(..))")
public void doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("----环绕通知 前-----");
Object object = proceedingJoinPoint.proceed(); // 执行目标方法
System.out.println("----环绕通知 后-----");
}
@AfterThrowing 异常抛出通知
通过设置throwing属性,可以设置发生异常对象参数
@AfterThrowing(value = "execution(* com.yu.demo1.UserDao.update(..))")
public void doAfterThrowing(Throwable e) throws Throwable {
System.out.println("----异常跑出通知-----");
}
@After 最终通知
无论是否出现异常,最终通知总是会被执行的
@After(value = "execution(* com.yu.demo1.UserDao.select(..))")
public void doAfter() {
System.out.println("----最终通知----");
}
通过@Pointcut为切点命名
在每个通知内定义切点,会造成工作量大,不易维护,对于重复的切点,可以使用@Pointcut进行定义
切点方法:private void 无参数方法,方法名为切点名
当通知多个切点时,可以使用 || 进行连接
@AfterReturning(value="myPointcut2()",returning = "result")
public void afterReturing(Object result){
System.out.println("后置通知=================="+result);
}
@Around(value="myPointcut3()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("环绕前通知================");
Object obj = joinPoint.proceed(); // 执行目标方法
System.out.println("环绕后通知================");
return obj;
}
@Pointcut(value="execution(* com.imooc.aspectJ.demo1.ProductDao.update(..))")
private void myPointcut2(){}
@Pointcut(value="execution(* com.imooc.aspectJ.demo1.ProductDao.delete(..))")
private void myPointcut3(){}
基于AspectJ的XML方式的AOP开发
使用XML配置切面
切面类
public class MyAspectXml {
// 前置通知
public void before(JoinPoint joinPoint){
System.out.println("XML方式的前置通知=============="+joinPoint);
}
// 后置通知
public void afterReturing(Object result){
System.out.println("XML方式的后置通知=============="+result);
}
// 环绕通知
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("XML方式的环绕前通知==============");
Object obj = joinPoint.proceed();
System.out.println("XML方式的环绕后通知==============");
return obj;
}
// 异常抛出通知
public void afterThrowing(Throwable e){
System.out.println("XML方式的异常抛出通知============="+e.getMessage());
}
// 最终通知
public void after(){
System.out.println("XML方式的最终通知=================");
}
}
切面类的配置
<!--配置切面类-->
<bean id="myAspectXml" class="com.imooc.aspectJ.demo2.MyAspectXml"/>
配置AOP完成增强
<!--aop的相关配置=================-->
<aop:config>
<!--配置切入点-->
<aop:pointcut id="pointcut1" expression="execution(* com.imooc.aspectJ.demo2.CustomerDao.save(..))"/>
<aop:pointcut id="pointcut2" expression="execution(* com.imooc.aspectJ.demo2.CustomerDao.update(..))"/>
<aop:pointcut id="pointcut3" expression="execution(* com.imooc.aspectJ.demo2.CustomerDao.delete(..))"/>
<aop:pointcut id="pointcut4" expression="execution(* com.imooc.aspectJ.demo2.CustomerDao.findOne(..))"/>
<aop:pointcut id="pointcut5" expression="execution(* com.imooc.aspectJ.demo2.CustomerDao.findAll(..))"/>
<!--配置AOP的切面-->
<aop:aspect ref="myAspectXml">
<!--配置前置通知-->
<aop:before method="before" pointcut-ref="pointcut1"/>
<!--配置后置通知-->
<aop:after-returning method="afterReturing" pointcut-ref="pointcut2" returning="result"/>
<!--配置环绕通知-->
<aop:around method="around" pointcut-ref="pointcut3"/>
<!--配置异常抛出通知-->
<aop:after-throwing method="afterThrowing" pointcut-ref="pointcut4" throwing="e"/>
<!--配置最终通知-->
<aop:after method="after" pointcut-ref="pointcut5"/>
</aop:aspect>
</aop:config>
ps: execution表达式-切面排除某个方法
@Pointcut("execution(* com.tellhow.app.controller..*.*(..)) && !execution(* com.tellhow.app.controller..*.action(..))")