[Spring 04] AOP三种实现方式

Spring_04 AOP


5. AOP

1. AOP在Spring中的作用

允许用户自定义切面, 提供声明式事务

横切关注点: 跨越应用程序多个模块的方法和功能(与业务逻辑无关)如日志,安全,缓存,事务

ASPECT 切面: 横切关注点 被模块化的的对象(如Log类)

Advice 通知: 切面需要完成的工作 Log中的一个方法

Target 目标: 被通知的对象

Proxy 代理: 向目标对象应用 通知 ,之后创建的对象

PointCut 切入点: 切面通知 执行的“地点”的定义

JointPoint 连接点: 与切入点匹配的执行点

[Spring 04] AOP三种实现方式

Advice类型:

MethodBeforeAdvice, AfterReturningAdvice, MethodInterceptor, ThrowsAdvice, IntroductionInterceptor

前置通知, 后置通知, 环绕通知, 异常抛出通知, 引介通知

AOP在不改变原有代码的方式下,增加新功能

导入maven包:

aspectjweaver: 织入包

2. Spring API接口实现AOP

写好怎删改查的接口和实现类: UserService和UserServiceImpl

写Log类:

public class BeforeLog implements MethodBeforeAdvice {
    public void before(Method method, Object[] objects, Object o) throws Throwable {
        System.out.println(o.getClass().getName()+"类的"+method.getName()+"被执行了");
    }
}

在beans.xml中注册:

<?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: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">
    <bean id="userServiceImpl" class="com.roy.service.UserServiceImpl"/>
    <bean id="beforeLog" class="com.roy.log.BeforeLog"/>
    <bean id="afterLog" class="com.roy.log.AfterLog"/>

    <aop:config>
        <aop:pointcut id="pointcut" expression="execution(* com.roy.service.UserServiceImpl.*(..))"/>
        <aop:advisor advice-ref="beforeLog" pointcut-ref="pointcut"/>
        <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
    </aop:config>
</beans>
  • 头文件中添加aop约束

  • aop标签中添加两个元素: 切入点通知

  • 测试类中正常调用

其中,切入点的expression是一个表达式,固定为: *表示通配符,..表示任意参数

execution(要执行的位置! (*(修饰词) *(返回值) *(类名) *(方法名) *(参数)))

3. 切面定义实现AOP

缺点:过程中无法添加和上述方法一样的,对业务类的交互(通过反射获取名称等)

写Aspect切面类: 其中包含 Advice通知;对于这部分的定义在xml文件中才说明。

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

xml文件中,先注册AspectLog的bean,再定义切面:

<aop:config>
    <aop:aspect id="" ref="aspectLog">定义切面(定义切入点,定义通知
        <aop:pointcut id="pointcut" expression="execution(* com.roy.service.UserServiceImpl.*(..))"/>
        <aop:before method="before" pointcut-ref="pointcut"/>
        <aop:after method="after" pointcut-ref="pointcut"/>
    </aop:aspect>
</aop:config>

4. 注解实现AOP

Aspect类:(注解不要导错包,都是Aspectj下的)

@Aspect
public class AnnotationLog {
    @Before("execution(* com.roy.service.UserServiceImpl.*(..))")
    public void before(){
        System.out.println("before");
    }
    @After("execution(* com.roy.service.UserServiceImpl.*(..))")
    public void after(){
        System.out.println("after");
    }
    @Around("execution(* com.roy.service.UserServiceImpl.*(..))")
    public void around(ProceedingJoinPoint pj) throws Throwable {
        System.out.println("around_Before");
        pj.proceed();//表示在这里执行业务的方法
        System.out.println("around_After");
    }
}

ProceedingJointPoint类:可以通过这个类实现第二种方式中无法和业务类交互的东西:

如: .proced()表示指定业务类实现的位置

.getSignature()表示获取在业务类中正在执行的方法名

.get*, 可以获得更多信息

xml中注册: (注意添加对aspect注解的支持

<bean id="userServiceImpl" class="com.roy.service.UserServiceImpl"/>
<bean id="annotationLog" class="com.roy.log.AnnotationLog"/>
<aop:aspectj-autoproxy/><!--添加对aspect注解的支持 -->

Spring中动态代理的实现方式:

基于接口的JDK,和基于类的cgLib

<aop:aspectj-autoproxy proxy-target-class="false"时,(默认为false, 使用JDK产生代理类

<aop:aspectj-autoproxy proxy-target-class="true"时,使用cgLib产生代理类

区别: (存疑)实测目标类没有接口,都能实现

  • 当被代理类是通过接口实现的,则用JDK(通过动态代理实现);

  • 当被代理类是一个类, CGLIB通过字节码生成子类,继承被代理类来实现代理。


Spring5版本对around、before、after的执行顺序:

around_Before 环绕
before
方法执行
afterReturning
after
around_After 环绕
上一篇:Spring 初始化流程


下一篇:【计题04组01号】编程入门训练