当前位置:   article > 正文

Spring基于AOP(面向切面编程)开发

Spring基于AOP(面向切面编程)开发

概述

        AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

为什么要学习AOP

在不修改源代码的情况下,对原方法进行增强

AOP可以校验,日志记录,性能监控,事务控制

底层实现(了解)

代理机制:

Spring的AOP的底层用到两种代理机制

        JDK动态代理:针对实现了接口的类产生的代理

        Cglib动态代理:针对没有接口的类产生的代理,应用了底层的字节码增强的技术,生成当前的子类对象

JDK动态代理

创建一个代理类

  1. public class ProxyUser implements InvocationHandler {
  2. private Object target; // 代理的目标对象
  3. public LogJdkProxy(Object target) {
  4. this.target = target;
  5. }
  6. /** 创建代理对象 */
  7. public Object createProxyInstance() {
  8. //1个参数设置代码使用的类装载器,一般采用跟目标类相同的类装载器
  9. //2个参数设置代理类实现的接口
  10. //3个参数设置回调对象,当代理对象的方法被调用时,会调用该参数指定对象的invoke方法
  11. return Proxy.newProxyInstance(//
  12. getClass().getClassLoader(), //1个参数
  13. target.getClass().getInterfaces(), //2个参数
  14. this); //3个参数
  15. }
  16. /**
  17. * @param proxy 目标对象的代理类实例
  18. * @param method 对应于在代理实例上调用接口方法的Method实例
  19. * @param args 传入到代理实例上方法参数值的对象数组
  20. * @return 方法的返回值,没有返回值(void)时是null
  21. */
  22. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  23. System.out.println("== Log:开始执行操作,方法名:"+method.getName()+" ==");
  24. Object result = method.invoke(target, args); // 执行原方法,把方法调用委派给目标对象
  25. System.out.println("== Log:操作执行完毕 ==");
  26. return result;
  27. }
  28. }

测试

Cglib动态代理

创建对象接口

  1. // 此类不能是final的,否则不能有子类,CGLIB也就不能工作了
  2. public class UserServiceImpl {
  3.  
  4. // 这是final的方法,不能被子类重写,所以CGLIB不会拦截这个方法
  5. public final void foo1() {
  6. System.out.println(">> final的方法 <<");
  7. }
  8.  
  9. // 这是static的方法,CGLIB不会拦截这个方法
  10. public static void foo2() {
  11. System.out.println(">> static的方法 <<");
  12. }
  13.  
  14. // 这是private的方法,CGLIB不会拦截这个方法
  15. private void foo3() {
  16. System.out.println(">> private的方法 <<");
  17. }
  18.  
  19. // CGLIB会拦截这个方法,可以是public, protected, default的修饰符
  20. public void deleteUser() {
  21. System.out.println(">> 删除一个User <<");
  22. }
  23. }

创建Cglib代理类

  1. // CGLIB代理类
  2. public class LogCglibProxy implements MethodInterceptor {
  3. private Object target; // 代理的目标对象
  4. /**
  5. * 创建代理对象
  6. * @param <T>
  7. * @param target 目标对象
  8. */
  9. public <T> T createProxyInstance(T target) {
  10. this.target = target;
  11. Enhancer enhancer = new Enhancer(); // 该类用于生成代理对象
  12. enhancer.setSuperclass(target.getClass()); // 设置父类
  13. enhancer.setCallback(this); // 设置回调对象为自己这个对象
  14. return (T) enhancer.create(); // 创建代理对象并返回
  15. }
  16. /**
  17. * @param proxy 目标对象代理类的实例
  18. * @param method 代理类实例上调用父类方法的Method实例
  19. * @param args 传入到方法参数值的对象数组
  20. * @param methodProxy 使用它调用父类的方法
  21. */
  22. @Override
  23. public Object intercept(Object proxy, Method method, Object[] args,
  24. MethodProxy methodProxy) throws Throwable {
  25. System.out.println(proxy.getClass());
  26. System.out.println("== Log:开始执行操作,方法名:" + method.getName() + " ==");
  27. Object result = methodProxy.invoke(target, args); // 执行原方法
  28. System.out.println("== Log:操作执行完毕 ==");
  29. return result;
  30. }
  31. }

测试

  1. public class MainTest {
  2. @Test
  3. public void test() throws Exception {
  4. UserService userService = new UserService();
  5. userService = (UserService) new LogCglibProxy().createProxyInstance(userService); // 使用包装之的后的代理对象
  6. userService.saveUser();
  7. System.out.println();
  8. userService.deleteUser();
  9. System.out.println();
  10. }
  11. }

Spring使用AspectJ进行AOP开发

引入lib包

引入配置文件

  1. <beans xmlns="http://www.springframework.org/schema/beans"
  2. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="
  4. http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
  5. http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
  6. </beans>
使用xml配置文件形式

通知类型

切入点表达式

编写一个切面类

  1. public class MyAspectXml {
  2. // 前置增强
  3. public void before(){
  4. System.out.println("前置增强===========");
  5. }
  6. }

在application Context.xml中配置

  1. <!-- 配置切面类 -->
  2. <bean id="myAspectXml" class="cn.test.spring.demo3.MyAspectXml"></bean>
  3. <!-- 进行 aop 的配置 -->
  4. <aop:config>
  5. <!-- 配置切入点表达式:哪些类的哪些方法需要进行增强 -->
  6. <aop:pointcut expression="execution(* cn.test.spring.demo3.OrderDao.save(..))" id="pointcut1"/>
  7. <!-- 配置切面 -->
  8. <aop:aspect ref="myAspectXml">
  9. <aop:before method="before" pointcut-ref="pointcut1"/> </aop:aspect>
  10. </aop:config>
使用注解来实现切面类

开启aop注解自动代理

AspectJ的AOP注解

@Aspect  定义切面类

通知类型

@Before        前置通知

@AfterReturing        后置通知

@Around        环绕通知

@After        最终通知

@AfterThrowing        异常抛出通知

@Pointcut        定义切入点

编写切面类

  1. @Component
  2. @Aspect
  3. public class MyAspect {
  4. @Before("MyAspect.pointcut01()")
  5. public void before(){
  6. System.out.println("前置-----");
  7. }
  8. @After("MyAspect.pointcut01()")
  9. public void after(){
  10. System.out.println("后置-----");
  11. }
  12. @Pointcut("execution(* com.xuexi.dao.*.*(..))")
  13. public void pointcut01(){
  14. }
  15. }

测试

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/article/detail/41552
推荐阅读
相关标签
  

闽ICP备14008679号