W
e
l
c
o
m
e
: )

Spring AOP面向切面

Spring AOP

  • Spring AOP -Aspect Oriented Programming 面向切面编程
  • AOP的做法是将 普通与业务无关 的功能抽象封装为 切面类
  • 切面配置目标方法 的执行前、执行后,真正做到即插即用

AOP概念

Spring AOP与AspectJ的关系

  • Eclipse AspectJ,一种基于Java平台的面向切面编程的语言
  • Spring AOP使用AspectJWeaver实现类与方法匹配
  • Spring AOP利用代理模式实现对象运行时功能扩展

关键概念

image-20220807173500225

AOP配置过程

  1. 依赖AspectJ
<!--Aspectjweaver是Spring AOP的底层依赖-->
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.5</version>
</dependency>
  1. 实现切面类/方法
public class MethodAspect {
    //切面方法,用于扩展额外功能
    //JoinPoint 连接点,通过连接点可以获取目标类/方法信息
    public void printExecutionTime(JoinPoint joinPoint) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyy-MM-dd HH:mm:ss SSS");
        String now = sdf.format(new Date());
        String className = joinPoint.getTarget().getClass().getName(); //获取目标类的名称
        String methodName = joinPoint.getSignature().getName(); //获取目标方法名称
        System.out.println("----->" + now + ":" + className + "." + methodName);
    }
}
  1. 配置Aspect Bean
<bean id="methodAspect" class="com.hua.spring.aop.aspect.MethodAspect"></bean>
  1. 定义切点(PointCut)
  2. 配置通知(Adivce)
<aop:config>
    <aop:pointcut id="pointcut" expression="execution(public * com.hua..*.*(..))"></aop:pointcut>
    <!-- 定义切面类 -->
    <aop:aspect ref="methodAspect">
        <!-- before通知(Advice),代表在目标方法运行前先执行methodAspect.printExecutionTime() -->
        <aop:before method="printExecutionTime" pointcut-ref="pointcut"/>
    </aop:aspect>
</aop:config>

JoinPoint对象

注解 说明
Object getTarget() 获取IoC容器内目标对象
Signature getSignature() 获取目标方法
Object[] getArgs() 获取目标方法参数

PointCut切点表达式

image-20220808190452026

AOP通知

image-20220808194356419

特殊的“通知” -引介增强

  • 引介增强(IntroductionInterceptor)是对类的增强,而非方法
  • 允许在运行时为目标类增加新属性或方法
  • 允许在运行时改变类的行为,让类随运行环境动态变更

环绕通知

**ProceedingJoinPoint **是JoinPoint的升级版,在原有功能外,还可以控制目标方法是否执行

基于注解开发AOP

@Component  //标记当前类为IoC组件
@Aspect     //说明当前类是切面类
public class MethodCheker {
    //环绕通知(切点表达式)
    @Around("execution(* com.hua..*Service.*(..))")
    public Object check(ProceedingJoinPoint pjp) throws Throwable {
        try {
            Long startTime = new Date().getTime();
            Object proceed = pjp.proceed();
            Long endTime = new Date().getTime();
            Long duration = endTime - startTime;
            if (duration >= 1000) {
                String className = pjp.getTarget().getClass().getName();
                String methodName = pjp.getSignature().getName();
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
                String now = sdf.format(new Date());
                System.out.println("---->" + now + ":" + className + "." + methodName + "(" + duration + "ms)<----");
            }
            return proceed;
        } catch (Throwable e) {
            throw e;
        }
    }
}

AOP代理模式应用

Spring基于代理模式实现功能动态扩展,包含两种形式:

  1. 目标拥有接口,通过JDK动态代理实现功能扩展
  2. 目标没有接口,通过CGLib组件实现功能扩展

代理模式-静态代理

  • 代理模式通过代理对象对原对象实现功能扩展

image-20220809225522389

代理模式-JDK动态代理

  • 根据接口动态的生成代理类
  • 必须实现接口才可以运行
/**
 * InvocationHandler是JDK提供的反射类,用于在JDK动态代理中对目标方法进行增强
 * InvocationHandler实现类与切面类的环绕通知类似
 */
public class ProxyInvocationHandler implements InvocationHandler {
    private Object target; //目标对象

    public ProxyInvocationHandler(Object target) {
        this.target = target;
    }

    /**
     * 在 invoke() 方法对目标方法进行增强
     *
     * @param proxy  代理类对象
     * @param method 目标方法
     * @param args   目标方法参数
     * @return 目标方法实参
     * @throws Throwable 目标方法抛出异常
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("----" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS").format(new Date()) + "----");
        Object ret = method.invoke(target, args);//调用目标方法
        return ret;
    }

    public static void main(String[] args) {
        UserService userService = new UserServiceImpl();
        ProxyInvocationHandler invocationHandler = new ProxyInvocationHandler(userService);
        // 动态创建代理类
        UserService userServiceProxy = (UserService)Proxy.newProxyInstance(userService.getClass().getClassLoader(),
                userService.getClass().getInterfaces(),
                invocationHandler);
        userServiceProxy.createUser();
    }
}

CGLib实现代理类

  • CGLib是运行时字节码增强技术
  • Spring AOP扩展无接口类使用CGLib
  • AOP会运行时生成目标继承类字节码的方式进行行为扩展

image-20220809235659937

posted @ 2022-12-02 19:16  与你一起看星辰  阅读(58)  评论(0)    收藏  举报