- AOP:面向切面编程
- 什么是AOP ? 使用代理技术,在不修改代码的基础上,对已有方法进行增强。
-
目标类:Dog
package com.czxy.demo15_aop.domain; import org.aspectj.lang.annotation.Before; import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; @Component public class Dog { public void eat() { System.out.println(" aop dog 正在吃..."); } } -
配置类:
package com.czxy.demo15_aop.config; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @Configuration @ComponentScan(basePackages = {"com.czxy.demo15_aop.domain","com.czxy.demo15_aop.aop"}) public class Demo15Configuration { } -
测试类
package com.czxy.demo15_aop; import com.czxy.demo15_aop.config.Demo15Configuration; import com.czxy.demo15_aop.domain.Dog; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringRunner; import javax.annotation.Resource; @RunWith(SpringRunner.class) @ContextConfiguration(classes = Demo15Configuration.class) public class TestDemo15 { @Resource private Dog dog; @Test public void testDemo15() { dog.eat(); } } -
修改配置类,开启AOP编程
@EnableAspectJAutoProxy //开启AOP
-
编写切面类 MyAspect,对目标类的方法进行增强
package com.czxy.demo15_aop.aop; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.springframework.stereotype.Component; @Component //将当前类,添加到spring容器中 @Aspect //切面编程注解 public class MyAspect { // 切入点表达式: 方法签名 // @注解("execution(返回值类型 包名.类名.方法名(参数类型))") @Before("execution(void com.czxy.demo15_aop.domain.Dog.eat())") public void init() { System.out.println(" 15 初始化"); } }
-
目标类:
package com.czxy.demo16_aop.dao; import org.springframework.stereotype.Repository; @Repository public class UserDao { public void insertUser() { System.out.println("添加"); } public void updateUser() { System.out.println("更新"); } } -
配置类
package com.czxy.demo16_aop.config; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.EnableAspectJAutoProxy; @Configuration @ComponentScan(basePackages = {"com.czxy.demo16_aop"}) @EnableAspectJAutoProxy //开启AOP public class Demo16Configuration { } -
测试类
package com.czxy.demo16_aop; import com.czxy.demo15_aop.config.Demo15Configuration; import com.czxy.demo15_aop.domain.Dog; import com.czxy.demo16_aop.config.Demo16Configuration; import com.czxy.demo16_aop.dao.UserDao; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringRunner; import javax.annotation.Resource; @RunWith(SpringRunner.class) @ContextConfiguration(classes = Demo16Configuration.class) public class TestDemo16 { @Resource private UserDao userDao; @Test public void testDemo15() { userDao.insertUser(); System.out.println("----------"); userDao.updateUser(); } } -
切面类
package com.czxy.demo16_aop.aop; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.springframework.stereotype.Component; @Component @Aspect public class MyAspect { @Before("execution(void com.czxy.demo16_aop.dao.UserDao.*User())") public void start() { System.out.println("开启事务"); } @After("execution(void com.czxy.demo16_aop.dao.UserDao.*User())") public void commit() { System.out.println("提交事务"); } }
- 目标类:需要被增强的类、代理的目标对象。
- 连接点:目标类可能被增强的每一个方法。
- 切入点:特殊的连接点,已经被增强了。
- 通知/增强:增强的方法
-
作用:将通知/增强作用于具体切入点
-
基本格式:
指示符(表达式) 1.指示符分类: 【execution】:用于匹配方法执行的连接点; within:用于匹配指定类型内的方法执行; this:用于匹配当前AOP代理对象类型的执行方法;注意是AOP代理对象的类型匹配,这样就可能包括引入接口也类型匹配; target:用于匹配当前目标对象类型的执行方法;注意是目标对象的类型匹配,这样就不包括引入接口也类型匹配; args:用于匹配当前执行的方法传入的参数为指定类型的执行方法; @within:用于匹配所以持有指定注解类型内的方法; @target:用于匹配当前目标对象类型的执行方法,其中目标对象持有指定的注解; @args:用于匹配当前执行的方法传入的参数持有指定注解的执行; @annotation:用于匹配当前执行方法持有指定注解的方法; 2.表示式格式: execution([修饰符] 返回值类型 包名.类名.方法名(参数类型列表) [throws 异常]) 返回值: * 表示返回任意值 包名: com.czxy.user.dao 具体包名 com.czxy.*.dao 任意模块的dao com.czxy.*sys.dao 固定后缀的包 com.czxy.user.dao.. 任意子包 (dao.impl包) 类名 UserDao 具体类名 *Dao 固定后缀 User* 固定前缀 * 任意 方法: findAll 具体方法名 find* 固定前缀 *All 固定后缀 * 任意 (参数类型列表): () 无参 (int) 第一个整形参数 (int,int) 两个参数都是整形 (*) 任意一个参数 (..) 参数任意// 完整的实例代码 * * com.czxy.service..User*.select*(..) // 常见的写法 * com.czxy.service..*.*(..)
6 通知类型-
spring通知共5个分类:前置通知、后置通知、环绕通知、抛出异常通知、最终通知
try{ // 前置通知、环绕通知 // 目标类的方法 // 后置通知、环绕通知 } catch() { // 抛出异常通知 } finally { // 最终通知 } //前置通知 @Before //后置通知 @AfterReturning //环绕通知 @Around //抛出异常通知 @AfterThrowing //最终通知 @After
@Before("execution(* com.czxy.demo16_aop.dao..*.*(..))") public void myBeforeAdvice() { System.out.println("开启事务"); }6.2 后置通知// 返回值:类型 变量名 // 类型,必须是Object // 变量名,需要通过returning设置,且提供对应的方法参数 @AfterReturning(value="切入点表达式", returning = "返回值变量名") public void 方法名(Object 返回值变量名) { }@AfterReturning(value="execution(* com.czxy.demo16_aop.dao..*.*(..))", returning = "obj") public void myAfterReturningAdvice(JoinPoint joinPoint, Object obj) { System.out.println("目标类:" + joinPoint.getTarget()); System.out.println("方法名:" + joinPoint.getSignature().getName()); System.out.println("返回值:" + obj); System.out.println("提交事务"); }6.3 环绕通知// 环绕通知:必须手动执行目标方法(连接点) ProceedingJoinPoint 可执行连接点 @Around("myPointcut()") public Object myAroundAdvice(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { System.out.println("环绕前2"); // 执行目标 Object proceed = proceedingJoinPoint.proceed(); System.out.println("环绕后2"); return proceed; }6.4 异常通知// 异常通知,可以获得异常具体信息,异常类型(Throwable) 异常变量名 @AfterThrowing(value="execution(* com.czxy.demo16_aop.dao..*.*(..))",throwing = "e") public void myAfterThrowingAdvice(Throwable e) { System.out.println("异常通知:" + e.getMessage()); }6.5 最终通知@After("execution(* com.czxy.demo16_aop.dao..*.*(..))") public void myAfterAdvice() { System.out.println("释放资源"); }6.6 抽取切入点使用 @Pointcut 抽取切入点,通过 方法名 进行引用。
package com.czxy.demo16_aop.aop; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; import org.springframework.stereotype.Component; @Component @Aspect public class MyAspect2 { // 抽取公共切入点表达式 @Pointcut("execution(* com.czxy.demo16_aop.dao..*.*(..))") private void myPointcut() { } // 前置通知 // @Before("myPointcut()") public void myBeforeAdvice() { System.out.println("开启事务2"); } // 后置通知 // @AfterReturning(value="myPointcut()", returning = "obj") public void myAfterReturningAdvice(JoinPoint joinPoint, Object obj) { System.out.println("目标类2:" + joinPoint.getTarget()); System.out.println("方法名2:" + joinPoint.getSignature().getName()); System.out.println("返回值2:" + obj); System.out.println("提交事务2"); } // 环绕通知:必须手动执行目标方法(连接点) ProceedingJoinPoint 可执行连接点 @Around("myPointcut()") public Object myAroundAdvice(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { System.out.println("环绕前2"); // 执行目标 Object proceed = proceedingJoinPoint.proceed(); System.out.println("环绕后2"); return proceed; } // 异常通知,可以获得异常具体信息,异常类型(Throwable) 异常变量名 @AfterThrowing(value="myPointcut()",throwing = "e") public void myAfterThrowingAdvice(Throwable e) { System.out.println("异常通知2:" + e.getMessage()); } @After("myPointcut()") public void myAfterAdvice() { System.out.println("释放资源2"); } } -



