AOP

动态代理

public class Main {    public static void main(String[] args) {        Bean bean = (Bean) Enhancer.create(Bean.class, new MethodInterceptor() {            private Bean bean = new Bean();            @Override            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {                System.out.println(method);                return method.invoke(bean,objects);            }        });        bean.run();    }}class Bean{    public void run(){        System.out.println("bean run");    }}

AOP简介

20211520172

AOP术语:

使用xml时,后置通知与返回通知以及异常通知的执行顺序取决于配置顺序

编写切点

Spring借助AspectJ的切点表达式语言来定义切面

AspectJ指示器描述
arg()限制连接点匹配参数为指定类型的执行方法
@args()限制连接点匹配参数由指定注解标注的执行方法
execution()用于匹配是连接点的执行方法
this()限制连接点匹配AOP代理的Bean引用为指定类型的类
target()限制连接点匹配目标对象为指定类型的类
@target ()限制连接点匹配特定的执行对象,这些对象对应的类要具备指定类型的注解
within()限制连接点匹配指定的类型
@within()限制连接点匹配指定注解所标注的类型( 当使用Spring AOP时,方法定义在由指定的注解所标注的类里)
@annotation限制匹配带有指定注解连接点
execution(* wang.ismy.spring.service.Service.doSth(..))

execution

execution(*com.sample.service.impl..*.*(..)) 解释如下:

符号含义
execution ()表达式的主体
第一个"*"符号表示返回值的类型任意
com.sample.service.implAOP所切的服务的包名,即,我们的业务部分
包名后面的"."表示当前包及子包
第二个"*"表示类名,*即所有类。此处可以自定义,下文有举例
.*(..)表示任何方法名,括号表示参数,两个点表示任何参数类型

创建切面

@Aspect@Component@Slf4jpublic class ErrorPageAspect {    @Pointcut("@annotation(wang.ismy.zbq.annotations.ErrorPage)")    public void pointCut(){}    @Around("pointCut()")    public Object around(ProceedingJoinPoint joinPoint){        try {            return joinPoint.proceed();        } catch (Throwable throwable) {            ModelAndView modelAndView = new ModelAndView();            modelAndView.setViewName("error");            modelAndView.addObject("error",throwable.getMessage());            return modelAndView;        }    }}

使用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        https://www.springframework.org/schema/beans/spring-beans.xsd        http://www.springframework.org/schema/aop        https://www.springframework.org/schema/aop/spring-aop.xsd">    <aop:config>        <!--配置切面-->        <aop:aspect id="loggerAdvice" ref="logger">            <aop:around method="log" pointcut="execution(* wang.ismy.spring.service.Service.doSth(..))"/>        </aop:aspect>    </aop:config>    <bean class="wang.ismy.spring.service.impl.ServiceImpl"/>    <bean id="logger" class="wang.ismy.spring.Logger"/></beans>

AOP 原理

AbstractAutoProxyCreator 实现了BeanPostProcessor

通过在Bean 实例化后,通过动态代理的方式 createProxy 对 Bean进行一层包裹 返回代理完成后的Bean

AopProxy 目前Spring 有2种方式 :

  1. JDK 动态代理:如果 bean 实现了接口,会使用这种方式。这种方式性能较好
  2. CGLIB 动态代理:如果 bean 没有实现接口,会使用这种方式