再看Spring之AOP

1. AOP

面向切面编程(Aspect Oriented Programming),通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,调高程序的可重用性,提高开发效率。

即可以在不修改原有功能的前提下,在执行某功能时给其添加新的功能。
这里以登录为例:

  • 原有登录功能
    在这里插入图片描述

  • 在原有登录功能的前提下,新增鉴权功能:
    在这里插入图片描述

1.1 实现原理

AOP使用动态代理方式实现。

  • 有接口:JDK动态代理实现。
    这里依然使用登录来模拟。
    接口类:

    public interface UserService {
    
        void login();
    
    }
    

    实现类:

    public class UserServiceImpl implements UserService{
    
        @Override
        public void login() {
            // 模拟已经实现登录功能
            System.out.println("登录成功");
        }
    
    }
    

    代理过程: 创建接口实现类的代理对象来增强对象的方法,通过代理对象来实现增强的功能。

    在这里插入图片描述- 无接口:CGLIB动态代理。

    创建被代理类的子类代理对象从而实现方法增强。

    在这里插入图片描述

1.1.1 JDK动态代理实现
  • 接口
/**
 * @Description
 * @date 2022/5/28 20:00
 */
public interface UserService {

    void login();

}
  • 实现类
/**
 * @Description
 * @date 2022/5/28 20:00
 */
public interface UserService {

    void login();

}
  • 代理实现
/**
 * @Description JDK 动态代理实现类
 * @date 2022/5/28 19:59
 */
public class JdkMain {
    public static void main(String[] args) {
        // 接口数组
        Class[] interfaces = {UserService.class};

        // 定义被增强的接口
        UserService user = (UserService) Proxy.newProxyInstance(JdkMain.class.getClassLoader(), interfaces, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                // 实现增强过程:
                // 1. 创建当前接口的实现类对象
                UserServiceImpl userService = new UserServiceImpl();

                // 2. 被增强方法执行之前
                System.out.println("执行之前 - before" + method.getName());

                // 3. 执行被增强方法
                Object obj = method.invoke(userService);

                // 4. 执行增强方法之后执行
                System.out.println("执行之后 - after" + method.getName());

                return obj;
            }
        });

        user.login();
    }
}

1.2 AOP常见术语

  • 连接点:可以被被增强的方法;
  • 切入点:实际被增强的方法;
  • 通知(增强):增强实现的功能;
    类型:
    1. 前置通知:方法前面执行,对应:@Before
    2. 后置通知:方法后面执行,对应@AfterReturning
    3. 环绕通知:方法前后都执行,对应@Around
    4. 异常通知:方法出现异常时执行,对应@AfterThrowing
    5. 最终通知:无论是否存在异常都会执行,对应@After
  • 切面:把通知应用到切入点的过程。

1.3 AspectJ

不属于Spring的组成部分,是一个独立的AOP框架,但通常与Spring连用来实现AOP。

  • 依赖
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>5.2.8.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.8.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>5.2.8.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-expression</artifactId>
            <version>5.2.8.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.2</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.2.8</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>5.2.8.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.7</version>
        </dependency>
    </dependencies>
  • 切入点表达式:声明对类和方法进行增强。
    语法结构:execution([权限修饰符][返回类型][全路径类名][方法名称]([参数列表]))
    1. 返回类型可以省略;
    2. *可以表示全部;
    3. ..表示参数。

1.4 注解实现

  • 配置文件
<?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.jm.spring.*"/>

    <aop:aspectj-autoproxy/>
</beans>    
  • 被增强类
@Component
public class User {

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

}
  • 代理类
/**
 * @Description 代理增强类
 * @date 2022/5/28 20:44
 */
@Component
@Aspect
@Order(1) // 指定优先级,越小优先级越高
public class UserProxy {

    // 定义切入点
    @Pointcut(value = "execution(* com.jm.spring.AOP.annotation.User.testVoid())")
    public void userPoint(){

    }

    @Before("userPoint()")
    public void before(){
        System.out.println("前置增强");
    }

    @After("userPoint()")
    public void after(){
        System.out.println("最终增强");
    }

    @AfterReturning("userPoint()")
    public void afterReturning(){
        System.out.println("后置增强");
    }

    @AfterThrowing("userPoint()")
    public void afterThrowing(){
        System.out.println("异常增强");
    }

    @Around("userPoint()")
    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("环绕增强 - 前");

        // 执行被增强方法
        proceedingJoinPoint.proceed();

        System.out.println("环绕增强 - 后");

        return null;
    }

}
  • 测试类
/**
 * @Description
 * @date 2022/5/28 20:48
 */
public class AOPMain {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("scan.xml");
        User user = context.getBean("user", User.class);
        user.testVoid();
    }
}

1.5 xml方式

没学,不看,用不到。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值