spring-AOP

AOP

面向切面编程 ,利用AOP可以对业务的部分进行隔离,从而使得业务逻辑部分之间的耦合度降低,提高程序的可重复性。

一、AOP的底层原理

AOP的底层使用的是动态代理

(1). 有两种情况的动态代理

  • 有接口情况

    • 使用JDK的动态代理

      public interface UserDao{
          public int add(int a, int b);
          public String update(String id);
      }
      
      public class UserDaoImpl implements UserDao{
          public int add(int a, int b) {
              return a + b;
          }
          public String update(String id){
              return id;
          }
      }
      
      public class JdkProxy{
          public static void main(String[] args){
              Class[] interfaces = {UserDao.class};
              UserDao userDao = new UserDaoImpl();
              UserDao dao = Proxy.newProxyInstance(JdkProxy.class.getClassLoader(), interfaces, new UserDaoProxy(userDao));
              int res = dao.add(1, 2);
              System.out.println(res);
          }
      }
      class UserDaoProxy implements Proxy{
          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("方法执行之前");
              Object invoke = method.invoke(obj, args);
              System.out.println("方法执行之后");
              return invoke;
          }
      }
      
  • 没有接口情况

    • 使用cglib的动态代理
工厂模式创建
public class UserFactory{
    public static UserDao getUserDao(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean1.xml");
        User user = applicationContext.getBean("user",User.class);
        // 通过反射获取到类对象
        Class clazz = Class.forName(User.class);
        // 通过类对象的一个方法获取该对象实例
        return (UserDao)clazz.newInstance();
    }
}

二、 AOP术语

  • 连接点

    • 类里面的哪些方法可以被增强,这些方法称为连接点
  • 切入点

    • 实际被真正增强的方法,这些方法被称为切入点
  • 通知(增强)

    • 实际增强的逻辑部分被称为通知
    • 通知有多种类型
      • 前置通知
      • 后置通知
      • 环绕通知
      • 异常通知
      • 最终通知
  • 切面

    • 把通知应用到切入点的过程就是切面

三、AOP操作

spring框架一般基于AspectJ实现AOP操作

AspectJ: 并不是spring的组成部分,独立AOP框架,一般把AspectJ和spring框架一起使用,进行AOP操作

准备工作

引入aop的依赖spring-aspectj.jar,aop-alliance.jar,aspectjweaver.jar,com.springsource.net.sf.cglib.jar

配置文件表头信息

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       <!-- p命名空间使用 -->
       xmlns:p="http://www.springframework.org/schema/p"
		<!-- 扫描注解包使用 -->
       xmlns:context="http://www.springframework.org/schema/context"
		<!-- aop使用 -->
       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
                            http://www.springframework.org/schema/context   http://www.springframework.org/schema/context/spring-context.xsd">
</beans>

切入点表达式

作用:知道对哪个类里面的哪个方法进行增强

语法结构:execution([权限修饰符][返回值类型][方法名称]([参数列表]))

<!-- 对com.wyxz.dao.Book对add方法增强 -->
execution(*com.wyxz.dao.Book.add(..))
<!-- 对com.wyxz.dao.Book对所有方法增强 -->
execution(*com.wyxz.dao.Book.*(..))
<!-- 对com.wyxz.dao.Book对所有类所有方法增强 -->
execution(*com.wyxz.dao.*.*(..))

四、基于xml配置文件实现

  1. 创建两个类,一个增强类,一个被增强类

    public class Book {
    
        public void buy() {
            System.out.println("买数~~~");
        }
    }
    
    public class BookProxy {
    
        public void before() {
            System.out.println("before~~~");
        }
    }
    
  2. 在spring配置文件中,创建两个类对象进行配置

    <bean id="Book" class="com.wyxz.config.Book"></bean>
    <bean id="bookProxy" class="com.wyxz.config.BookProxy"></bean>
    
  3. 在spring配置文件中,配置切入点

    <!--    配置aop增强   -->
    <aop:config>
    		<!-- 这里的id为p表示的是要切的是哪个类,id的值可以自定义,expression中就是对这个类中的哪个方法进行增强 -->
        <aop:pointcut id="p" expression="execution(* com.wyxz.config.Book.buy(..))"/>
        <!-- 声明切入点是哪个类 -->
        <aop:aspect ref="bookProxy">
        		<!--    配置切面
                   method:表示使用哪个方法
                   pointcut-ref : 切入点使用在哪个类的哪个方法上
           -->
            <aop:before method="before" pointcut-ref="p"/>
        </aop:aspect>
    </aop:config>
    

五、基于注解方式实现(常用)

  1. 创建类,在类里面定义方法

    @Component
    public class User{
        public void add(){
            System.out.println("add~~~");
        }
    }
    
  2. 创建一个类(增强类), 让不同的类代表不同的增强

    @Component
    @Aspect
    public class UserProxy {
    
        // 前置通知
        @Before(value = "execution(* com.wyxz..annotation.User.add(..))")
        public void before() {
            System.out.println("before~~~");
        }
    	// 当增强的方法发生异常的时候执行
        @AfterThrowing(value = "execution(* com.wyxz..annatation.User.add(..))")
        public void afterThrowsing() {
            System.out.println("after~~~");
        }
    	// 当增强方法执行之后执行
        @After(value = "execution(* com.wyxz..annotation.User.add(..))")
        public void after() {
            System.out.println("after~~~");
        }
    	// 当增强方法返回之后执行
        @AfterReturning(value = "execution(* com.wyxz.annotation.User.add(..))")
        public void afterReturning() {
            System.out.println("afterReturning~~~");
        }
    	// 在增强方法执行前后都会执行
        @Around(value = "execution(* com.wyxz.annatation.User.add(..))")
        public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
            System.out.println("around之前~~~");
            proceedingJoinPoint.proceed();
            System.out.println("around之后~~~");
        }
    }
    
  3. 进行通知的配置

    1. 在spring配置文件中,开启注解扫描

      <context:component-scan base-package="com.wyxz.annotation"></context:component-scan>
      
    2. 使用注解创建User和UserProxy对象

      @Component
      // 在上面两个类上边加上这个注解
      
    3. 在增强类上面添加注解@AspectJ

      // 在UserProxy中添加注解
      @Aspect
      
    4. 在spring配置文件中开启生成代理对象

      <!-- 开启注解扫描 -->
      <context:component-scan base-package="com.wyxz.annotation"></context:component-scan>
      <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
      
    5. 使用class配置类的方式(不适用xml配置文件,完全配置类实现方式)

      @Configuration
      @ComponentScan(basePackages = "com.wyxz")
      @EnableAspectJAutoProxy(proxyTargetClass = true)
      public class Config {
      }
      
  4. 配置不同类型的通知

    1. 在增强类里面,在作为通知方法上面添加通知类型注解,使用切入点表达式配置

      // 在UserProxy中的方法中添加如下内容
      @Before(value = "execution(* com.wyxz..annotation.User.add(..))")
      @AfterThrowing(value = "execution(* com.wyxz..annatation.User.add(..))")
      @AfterReturning(value="execution(* com.wyxz.annatation.User.add(..))")
      @Around(value="execution(* com.wyxz.annatation.User.add(..))")
      @After(value="execution(* com.wyxz.annatation.User.add(..))")
      
  5. 将表达式的公式抽取使用

    @PointCut(value="execution(* com.wyxz.annatation.User.)")
    public void point(){
        
    }
    @Before(value = "point()")
        public void before() {
            System.out.println("before~~~");
        }
    
  6. 设置增强类的优先级

    //在增强类上加注解@Order()值越小优先级越高
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码农先生eee

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值