(1)面向切面编程(方面),利用 AOP 可以对业务逻辑的各个部分进行隔离,从而使得
业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
(2)通俗描述:不通过修改源代码方式,在主干功能里面添加新功能
(3)使用登录例子说明 AOP
(1)有两种情况动态代理
第一种 有接口情况,使用 JDK 动态代理,创建接口实现类代理对象,增强类的方法.
使用 Proxy 类里面的方法创建代理对象
方法有三个参数:
第一参数,类加载器
第二参数,增强方法所在类的接口,支持多个接口
第三参数,实现这个接口 InvocationHandler,创建代理对象,写增强的部分
UserDao
package com.limi.dao; public interface UserDao { void say(); }
UserDaoImp
package com.limi.dao; import org.springframework.stereotype.Repository; @Repository public class UserDaoImp implements UserDao{ @Override public void say(){ System.out.println("UserDaoImp say...."); } }
UserDaoProxy, 用于编写增强逻辑
package com.limi.dao; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; //创建代理对象代码 public class UserDaoProxy implements InvocationHandler { private Object obj; //把需要创建代理的对象传递进来 public UserDaoProxy(Object obj){ this.obj = obj; } //增强的逻辑 @Override public Object invoke(Object o, Method method, Object[] objects) throws Throwable { //方法之前执行 System.out.println("方法之前执行..."); //被增强方法的执行 Object res = method.invoke(obj, objects); //方法之后执行 System.out.println("方法之后执行..."); return res; } }
测试类MyTest
package com.limi.test; import com.limi.dao.UserDao; import com.limi.dao.UserDaoImp; import com.limi.dao.UserDaoProxy; import org.junit.Test; import java.lang.reflect.Proxy; public class MyTest { @Test public void test1(){ //需要增强方法的接口 Class interfaces[] = {UserDao.class}; //需要增强方法的对象 UserDaoImp userDaoImp = new UserDaoImp(); //获取方法被增强的对象 UserDao userDao = (UserDao)Proxy.newProxyInstance(MyTest.class.getClassLoader(), interfaces, new UserDaoProxy(userDaoImp)); //执行被增强的方法 userDao.say(); } }
测试结果
第二种 没有接口情况,使用 CGLIB 动态代理,创建子类的代理对象,增强类的方法.
3.AOP术语1.连接点
类里面哪些可以加入增强逻辑的方法, 这些方法称为连接点
2.切入点
实际被你增强了的方法
3.通知
实际增强的逻辑部分称为通知, 通知有多种类型:
前置通知
后置通知
环绕通知
异常通知
最终通知
4.切面
是一个动作, 把通知应用到切入点的过程
1、Spring 框架一般都是基于 AspectJ 实现 AOP *** 作,
AspectJ 不是 Spring 组成部分,独立 AOP 框架,一般把 AspectJ 和 Spirng 框架一起使用,进行 AOP *** 作.
2、基于 AspectJ 实现 AOP *** 作
有两种方式:
(1)基于 xml 配置文件实现
(2)基于注解方式实现
3、在项目工程里面引入 AOP 相关依赖
4、切入点表达式
(1)切入点表达式作用:知道对哪个类里面的哪个方法进行增强
(2)语法结构: execution([权限修饰符] [返回类型] [类全路径] [方法名称] ([参数列表]) )
举例 1:对 com.limi.dao.BookDao 类里面的 add 进行增强 execution(* com.limi.dao.BookDao.add(…))
举例 2:对 com.limi.dao.BookDao 类里面的所有的方法进行增强 execution(* com.limi.dao.BookDao.* (…))
举例 3:对 com.limi.dao 包里面所有类,类里面所有方法进行增强 execution(* com.limi.dao.. (…))
5.AOP代码实现1.基于完全注解方式
SpringConfig
package com.limi.config; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.EnableAspectJAutoProxy; @Configuration//配置类,代替xml配置文件 @ComponentScan(basePackages = {"com.limi"})// @EnableAspectJAutoProxy(proxyTargetClass = true)//开启 Aspect 生成代理对象 public class SpringConfig{ }
UserDao
package com.limi.dao; import org.springframework.stereotype.Component; //需要增强的类 @Component public class UserDao { public void say(){ System.out.println("UserDao say..."); } }
UserDaoProxy
package com.limi.dao; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; import org.springframework.stereotype.Component; //用于加入增强逻辑的类 @Component @Aspect //生成代理对象 public class UserDaoProxy { //前置通知 //@Before 注解表示作为前置通知 @Before(value = "execution(* com.limi.dao.UserDao.say(..))") public void before(){ System.out.println("before..."); } //后置通知(返回通知), 当有异常出现不执行 @AfterReturning(value = "execution(* com.limi.dao.UserDao.say(..))") public void afterReturning(){ System.out.println("afterReturning..."); } //最终通知 @After(value = "execution(* com.limi.dao.UserDao.say(..))") public void after(){ System.out.println("after..."); } //异常通知 @AfterThrowing(value = "execution(* com.limi.dao.UserDao.say(..))") public void afterThrowing(){ System.out.println("afterThrowing..."); } //环绕通知 @Around(value = "execution(* com.limi.dao.UserDao.say(..))") public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { System.out.println("环绕之前........."); //被增强的方法执行, 这里也就是执行UserDao里面的say()方法 //如果使用了环绕通知不执行 proceedingJoinPoint.proceed(); 则被增强的原方法内容不会执行, 只执行其他增强逻辑 proceedingJoinPoint.proceed(); System.out.println("环绕之后........."); } }
测试类MyTest
package com.limi.test; import com.limi.config.SpringConfig; import com.limi.dao.UserDao; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class MyTest { @Test public void test1(){ //1.加载配置类 ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class); //2.获取配置的对象, 参数1:bean的id值, 参数2: 类名.class UserDao userService = context.getBean("userDao", UserDao.class); //3.使用对象 userService.say(); } }
测试结果
①注意:@AfterReturning标注的方法当被增强的方法有异常出现时不执行, 执行的是@AfterThrowing标注的方法
UserDao的say()方法内加int a = 10/0; 测试异常情况
测试结果, 可以看到@AfterReturning标注的方法未执行, 执行的是@AfterThrowing标注的方法
②小技巧:使用@Pointcut提取公共切入点
UserDaoProxy
package com.limi.dao; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; import org.springframework.stereotype.Component; //用于加入增强逻辑的类 @Component @Aspect //生成代理对象 public class UserDaoProxy { //提取公共切入点,可减少代码量 @Pointcut(value = "execution(* com.limi.dao.UserDao.say(..))") public void pointCut(){ } //前置通知 //@Before 注解表示作为前置通知 @Before(value = "pointCut()") public void before(){ System.out.println("before..."); } //后置通知(返回通知), 当有异常出现不执行 @AfterReturning(value = "pointCut()") public void afterReturning(){ System.out.println("afterReturning..."); } //最终通知 @After(value = "pointCut()") public void after(){ System.out.println("after..."); } //异常通知 @AfterThrowing(value = "pointCut()") public void afterThrowing(){ System.out.println("afterThrowing..."); } //环绕通知 @Around(value = "pointCut()") public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { System.out.println("环绕之前........."); //被增强的方法执行, 这里也就是执行UserDao里面的say()方法 //如果使用了环绕通知不执行 proceedingJoinPoint.proceed(); 则被增强的原方法内容不会执行, 只执行其他增强逻辑 proceedingJoinPoint.proceed(); System.out.println("环绕之后........."); } }
测试结果
③多个增强类对同一个方法进行增强
(1)在增强类上面添加注解 @Order(数字类型值),数字类型值越小优先级越高, 同类型的方法, 优先级高的类的方法先执行.
第一个增强类:UserDaoProxy
package com.limi.dao; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; //用于加入增强逻辑的类 @Component @Aspect //生成代理对象 @Order(1) public class UserDaoProxy { //提取公共切入点,可减少代码量 @Pointcut(value = "execution(* com.limi.dao.UserDao.say(..))") public void pointCut(){ } //前置通知 //@Before 注解表示作为前置通知 @Before(value = "pointCut()") public void before(){ System.out.println("before..."); } //后置通知(返回通知), 当有异常出现不执行 @AfterReturning(value = "pointCut()") public void afterReturning(){ System.out.println("afterReturning..."); } //最终通知 @After(value = "pointCut()") public void after(){ System.out.println("after..."); } //异常通知 @AfterThrowing(value = "pointCut()") public void afterThrowing(){ System.out.println("afterThrowing..."); } //环绕通知 @Around(value = "pointCut()") public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { System.out.println("环绕之前........."); //被增强的方法执行, 这里也就是执行UserDao里面的say()方法 //如果使用了环绕通知不执行 proceedingJoinPoint.proceed(); 则被增强的原方法内容不会执行, 只执行其他增强逻辑 proceedingJoinPoint.proceed(); System.out.println("环绕之后........."); } }
第二个增强类:UserDaoProxy2
package com.limi.dao; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; //用于加入增强逻辑的类 @Component @Aspect //生成代理对象 @Order(2) public class UserDaoProxy2 { //提取公共切入点,可减少代码量 @Pointcut(value = "execution(* com.limi.dao.UserDao.say(..))") public void pointCut(){ } //前置通知 //@Before 注解表示作为前置通知 @Before(value = "pointCut()") public void before(){ System.out.println("UserDaoProxy2 before..."); } }
测试结果, 可以看到同样是前置通知before,由于UserDaoProxy2的优先级更低, 所以后执行.
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)