Spring的AOP实现

本文详细介绍了Spring的AOP(面向切面编程)概念,包括连接点、切入点、通知和切面等核心术语。通过JDK动态代理展示了如何创建接口代理对象,并提供了三种不同的实现方式。接着,探讨了AspectJ注解在Spring中的AOP应用,分别展示了通过Spring API和注解两种方式实现AOP操作。这些内容有助于理解并实践Spring的AOP功能,提升代码的可维护性和复用性。
摘要由CSDN通过智能技术生成

1、什么是AOP

(1)AOP为 Aspect Oriented Programming 的缩写,意为:面向切面编程,利用 AOP 可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
(2)通俗描述:不通过修改源代码方式,在主干功能里面添加新功能

2、AOP常见术语

  1. 连接点:类里面哪些方法可以被增强
  2. 切入点:实际中真正被增强的方法
  3. 通知:实际增强的逻辑部分(增强的功能实现)
  4. 切面:把通知应用到切入点的过程

3、AOP 底层使用动态代理

  1. 有接口情况,使用 JDK动态代理
    创建接口实现类代理对象,增强类的方法
  2. 没有接口情况,使用CGLIB动态代理
    创建子类的代理对象,增强类的方法

JDK 动态代理

在这里插入图片描述

  • 第一参数,定义代理类的类加载器
  • 第二参数,增强方法所在的类,这个类实现的接口,支持多个接口
  • 第三参数,实现这个接口 InvocationHandler,创建代理对象,写增强的部分

(1)创建接口,定义方法

public interface UserDao {
    public int add(int a,int b);
}

(2)创建接口实现类,实现方法

public class UserDaoImpl implements UserDao {
	@Override
	public int add(int a, int b) {
		 return a + b;
 	}
 }

(3)使用 Proxy 类创建接口代理对象

方法一

public class JDKProxy {
   public static void main(String[] args) {
		//创建接口实现类代理对象
		Class[] interfaces = {UserDao.class};
   		UserDaoImpl userDao = new UserDaoImpl();
   		UserDao dao = (UserDao) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(),
   			interfaces, new UserDaoProxy(userDao));
   		int result = dao.add(1, 2);
		System.out.println("result:"+result);
	} 
}

//创建代理对象代码
class UserDaoProxy implements InvocationHandler {
   //1 把创建的是谁的代理对象,把谁传递过来
   //有参数构造传递
   private Object obj;
   public UserDaoProxy(Object obj) {
		this.obj = obj;
   }
    //增强的逻辑
   @Override
   public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
   		//方法之前
   		System.out.println("方法之前执行...."+method.getName()+" :传递的参数..."+ Arrays.toString(args));
   		//被增强的方法执行
   		Object res = method.invoke(obj, args);
   		//方法之后
   		System.out.println("方法之后执行...."+obj);
   		return res;
   	} 
}

方法二:匿名内部类

public class JDKProxy {
   public static void main(String[] args) {
       Class[] interfaces = {UserDao.class};
       UserDaoImpl userDao = new UserDaoImpl();
       UserDao dao = (UserDao) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new InvocationHandler() {
           @Override
           public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
               System.out.println("方法之前执行...." + method.getName() + " :传递的参数..." + Arrays.toString(args));
               Object res = method.invoke(userDao, args);
               System.out.println("方法之后执行...." + userDao);
               return res;
           }
       });
       System.out.println("result:" + dao.add(1, 2));
   }
}

方法三:lamda表达式

public class JDKProxy {
    public static void main(String[] args) {
        Class[] interfaces = {UserDao.class};
        UserDaoImpl userDao = new UserDaoImpl();
        UserDao dao = (UserDao) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, (proxy, method, args1) -> {
            System.out.println("方法之前执行...." + method.getName() + " :传递的参数..." + Arrays.toString(args1));
            Object res = method.invoke(userDao, args1);
            System.out.println("方法之后执行...." + userDao);
            return res;
        });
        System.out.println("result:" + dao.add(1, 2));
    }
}

(4)结果

在这里插入图片描述

AspectJ注解实现AOP操作

(1)通过 Spring API 实现

首先先导入依赖包

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.7</version>
</dependency>

① 业务接口

@Component
public class User {
    public void add() {
        System.out.println("add......");
    }
}

② 增强类。 一个前置增强 一个后置增强。

@Component
public class UserProxy {
    public void before() {
        System.out.println("before.......");
    }

    public void after() {
        System.out.println("after.......");
    }

    public void around(ProceedingJoinPoint point) throws Throwable {
        System.out.println("环绕前......");
        point.proceed();
        System.out.println("环绕后......");
    }

    public void afterReturning() {
        System.out.println("afterReturning......");
    }

    public void afterThrowing() {
        System.out.println("afterThrowing......");
    }
}

③ 最后去spring的文件中注册 , 并实现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:context="http://www.springframework.org/schema/context"
       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/context
       http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd">

    <!-- 开启组件扫描包 -->
    <context:component-scan base-package="com.workhah"/>
    
    <aop:config>
        <aop:pointcut id="p" expression="execution(* com.workhah.pojo.User.add(..))"/>
        <aop:aspect ref="userProxy">
            <aop:before method="before" pointcut-ref="p"/>
            <aop:after method="after" pointcut-ref="p"/>
            <aop:after-returning method="afterReturning" pointcut-ref="p"/>
            <aop:after-throwing method="afterThrowing" pointcut-ref="p"/>
            <aop:around method="around" pointcut-ref="p"/>
        </aop:aspect>
    </aop:config>
</beans>

④ 测试

public class MyTest {
    @Test
    public void test(){
        ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
        User user = context.getBean("user", User.class);
        user.add();
    }
}

⑥ 结果
在这里插入图片描述

(2)注解实现

① 需要增强的类

@Component
public class User {
    public void add() {
        System.out.println("add......");
    }
}

② 增强类

@Component
@Aspect
public class UserProxy {
    @Before("execution(* com.workhah.pojo.User.add(..))")
    public void before() {
        System.out.println("before.......");
    }

    @After("execution(* com.workhah.pojo.User.add(..))")
    public void after() {
        System.out.println("after.......");
    }

    @Around("execution(* com.workhah.pojo.User.add(..))")
    public void around(ProceedingJoinPoint point) throws Throwable {
        System.out.println("环绕前......");
        point.proceed();
        System.out.println("环绕后......");
    }

    @AfterReturning("execution(* com.workhah.pojo.User.add(..))")
    public void afterReturning() {
        System.out.println("afterReturning......");
    }

    @AfterThrowing("execution(* com.workhah.pojo.User.add(..))")
    public void afterThrowing() {
        System.out.println("afterThrowing......");
    }
}

③ spring中配置

通过 aop 命名空间的<aop:aspectj-autoproxy />声明自动为 spring 容器中那些配置@aspectJ切面的bean创建代理。

<!-- 开启组件扫描包 -->
<context:component-scan base-package="com.workhah"/>
<!-- 开启Aspect生成代理对象 -->
<aop:aspectj-autoproxy/>

④ 结果
在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值