Spring5 学习笔记2

Spring 两大特性 :IOC和AOP,在Spring5 学习笔记1中已经对IOC有了详细的记录,此篇学习笔记主要记录AOP

概念

1、什么是AOP
(1)面相切面编程:利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发效率
(2)通俗描述:不修改源代码的前提,在原来的业务逻辑上进行功能增强。

底层原理

1、AOP底层是通过使用动态代理来实现的
(1)动态代理分成两种情况
第一种 JDK动态代理,主要是用来处理有实现接口的情况

  • 创建接口实现类代理对象,增强类的方法
  • 在这里插入图片描述
    调用newInstanceProxy方法
    在这里插入图片描述
    参数说明
    loader:类加载器
    interfaces:增强方法所在的类实现的接口,支持多个接口
    hadnler:实现这个接口InvocationHandler,创建代理对象,实现方法增强

举例说明

// 创建接口
public interface UserService {

    public void add();
}
// 创建实现类
public class UserServiceImpl implements UserService {
    @Override
    public void add() {
        System.out.println("UserServiceImpl....add");
    }
}
// 创建代理类
public class UserProxy implements InvocationHandler {

    private Object target;

   @Override
   public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("在干嘛呢。。。" + t.getClass().getName() + " ------ "+ method.getName());
        Object invoke = method.invoke(t, objects);
        System.out.println("好的吧。。。。");
        return invoke;
   }

    public void setTarget(Object target) {
        this.target = target;
    }
}
// 创建测试类
public class TestAop {

    @Test
    public void test() {
        UserProxy userProxy = new UserProxy();
        userProxy.setTarget(new UserServiceImpl());
        UserService o = (UserService)Proxy.newProxyInstance(this.getClass().getClassLoader(), UserServiceImpl.class.getInterfaces(), userProxy);
        o.add();
    }
}

输出结果
![在这里插入图片描述](https://img-blog.csdnimg.cn/43ad375616464fee94a6d2c2c94c1e13.png

第二种 CGLIB动态代理,主要是用来处理没有实现接口的情况

  • 创建子类的代理对象,增强类的方法
    在这里插入图片描述
    举例说明
// 创建被代理类
public class Student {

    public void read() {
        System.out.println("读书呢。。。。");
    }
}
// 创建代理类
public class StudentProxy<T> implements MethodInterceptor {

    private T t;

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("在干嘛呢。。。" + t.getClass().getName() + " ------ "+ method.getName());
        Object invoke = method.invoke(t, objects);
        System.out.println("好的吧。。。。");
        return invoke;
     }

    public T getT(T t) {
        this.t = t;
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(t.getClass());
        enhancer.setCallback(this);
        T o = (T)enhancer.create();
        return o;
    }


}
// 创建测试类
public class TestAop {

    @Test
    public void test2() {
        StudentProxy<Student> studentStudentProxy = new StudentProxy<>();
        Student t = studentStudentProxy.getT(new Student());
        t.read();
    }
}

测试结果
在这里插入图片描述

AOP术语

(1)连接点
类里面可以被增强的方法被称为连接点
(2)切入点
类里面实际被增强的方法被称为切入点
(3)通知(增强)
[1]实际增强的逻辑部分称为通知(增强)
[2]通知分为多种类型

  • 前置通知
  • 后置通知
  • 环绕通知(方法前后都会执行)
  • 异常通知
  • 最终通知(类似于finally,不管有不有异常都会执行)
    (4)切面
    [1]把通知应用到切入点的过程称为切面

准备

1、Spring框架一般都是基于AspectJ实现AOP操作

  • AspectJ不是Spring组成部分,是一个独立的AOP框架,一般把AspectJ和Spring组合使用,进行AOP操作
    2、基于AspectJ实现AOP操作
    (1)基于xml配置文件实现
    (2)基于注解方式实现
    3、引入相关依赖
    4、切入点表达式
    (1)切入点表达式作用:知道对哪个类里面的哪个类方法进行增强
    (2)语法结构
    execution([权限修饰符][返回类型][类全路径][增强的方法])
    例1:对com.company.spring7.BookDao类中的add方法增强
    execution(* com.company.spring6.BookDao.add(…))

例2:对com.company.spring7.BookDao类中的所有方法增强
execution(* com.company.spring6.BookDao.*(…))

AspectJ注解

1、创建一个被增强的类

@Service("bookDao")
public class BookDao {

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

2、创建aop类

@Component // 注册为一个Bean
@Aspect // 表明这是一个aop代理类
public class BookProxy {
    
    // 定义切入点,这样做的好处是不用在每个通知注解中都再次定义execution
    @Pointcut(value = "execution(* com.company.base.spring7.aopanno.BookDao.add(..))")
    public void advice() {

    }
    // 最终通知,不管是否发生异常都会执行
    @After("advice()")
    public void after(){
        System.out.println("最终增强啦");
    }
    // 前置通知,在方法执行前执行
    @Before("advice()")
    public void before() {
        System.out.println("前置增强啦");
    }
    // 环绕通知,如果无参的情况下只会在方法执行之后执行
    // 有ProceedingJoinPoint参数的情况,可以在ProceedingJoinPoint的proceed方法执行前后进行增强
    @Around("advice()")
    public void around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("环绕增强啦1");
        joinPoint.proceed();
        System.out.println("环绕增强啦2");
    }

    // 异常通知,只会在发生异常的情况才会执行
    @AfterThrowing("advice()")
    public void afterThrowing() {
        System.out.println("异常增强啦");
    }
    // 后置通知-也叫返回结果通知,方法正常执行完成之后才会执行
    @AfterReturning("advice()")
    public void afterReturning() {
        System.out.println("后置增强啦");
    }
}

3、创建注解配置类

@Configuration// 表明这是一个配置类
@ComponentScan(basePackages = {"com.company.base.spring7.aopanno"}) // 配置需要扫描的包
@EnableAspectJAutoProxy // 自动开启aop代理
public class SpringConfig {
}

4、执行测试

public class TestSpring7 {

    @Test
    public void test() {
        ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
        BookDao bookDao = context.getBean("bookDao", BookDao.class);
        bookDao.add();
    }
}

在这里插入图片描述
5、多个增强类的情况下,定义优先级
(1)添加注解@Order(数字类型值),值越小,优先级越高
在这里插入图片描述

AspectJ配置文件

1、创建UserDao类

public class UserDao {

    public void speak() {
        System.out.println("我在说话啦");
    }
}

2、创建aop代理类

public class UserProxy {
    public void before() {
        System.out.println("你能说话吗");
    }
}

3、引入aop命名空间
在这里插入图片描述
4、配置xml信息
在这里插入图片描述
5、测试结果
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值