java超快速入门(五):面向切面编程(AOP)

2021-09-29  本文已影响0人  自我De救赎

AOP原理

AOP是使用代理模式,在指定方法执行前、执行后等各个阶段进行自定义处理
下面所讲到的代理模式中,一共有两种类型,一种是基于接口的代理,一种是基于继承的代理

AOP术语

实现AOP模式

手动代理模式

使用Proxy.newProxyInstance()方法进行代理

Target target = new Target()
TargetInterface proxy = (TargetInterface)Proxy.newProxyInstance(Target.class.getClassLoader(), new Class[]{TargetInterface.class}, new InvocationHandler() {
    public Object before(Object proxy, Method method, Object[] args){
        System.out.println("执行" + method.getName() + "\r\n");
        return proxy;
    }
    public Object after(Object proxy, Method method, Object[] args, Object result){
        System.out.println("执行结果" + result.toString() + "\r\n");
        return result;
    }
    public Object exceptionHandler(Object proxy, Method method, Object[] args){
        return null;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        try{
            proxy = this.before(proxy, method, args);
            Object result = method.invoke(target, args);
            result = this.after(proxy, method, args, result);
            return result;
        }catch (Throwable throwable){
            return this.exceptionHandler(proxy, method, args)
        }
    }
});

cglib

cglib通过动态创建目标类的子类作为代理类来实现代理模式,cglib代理的好处是,目标类不需要实现任何接口,因为代理类是继承自目标类,因此有目标类的所有方法

先定义一个切面类

/** MyAspect.java **/
package com.sinbxeunha.josechan.aspect;

import org.aopalliance.intercept.MethodInvocation;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class MyAspect {
    public Object before(Object proxy, Method method, Object[] args, MethodProxy methodProxy){
        System.out.println("执行" + method.getName() + "\r\n");
        return null;
    }

    public Object after(Object proxy, Method method, Object[] args, MethodProxy methodProxy, Object result){
        assert result != null && result.toString() != null;
        System.out.println("执行结果:" + result.toString() + "\r\n");
        return result;
    }

    public Object exceptionHandler(Object proxy, Method method, Object[] args, MethodProxy methodProxy, Throwable throwable){
        System.out.println("结果异常:" + throwable.getMessage() + "\r\n");
        return null;
    }
}

使用cglib进行代理

//cglib代理
Target target = new Target();
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(target.getClass());
MyAspect aspect = new MyAspect();
enhancer.setCallback(new MethodInterceptor() {
    @Override
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        try{
            //前方法
            proxy = aspect.before(proxy, method, args, methodProxy);
            //下面两句是一样的
            Object result = method.invoke(target, args);
//                    Object result = Proxy.invokeSuper(target, args);
            //后方法
            return result = aspect.after(proxy, method, args, methodProxy, result);
        }catch (Throwable throwable){
            return aspect.exceptionHandler(proxy, method, args, methodProxy, throwable);
        }
    }
});

aopalliance

aop联盟定义了一系列规范,实现这些接口就能实现切面编程
同样的我们实现切面类

/*** MyAspect.java ***/
package com.sinbxeunha.josechan.aspect;

import org.aopalliance.intercept.MethodInvocation;

public class MyAspect {
    public Object before(MethodInvocation invocation){
        System.out.println("执行" + invocation.getMethod().getName() + "\r\n");
        return null;
    }

    public Object after(Object result){
        System.out.println("执行结果:" + result.toString() + "\r\n");
        return result;
    }

    public Object exceptionHandler(Throwable throwable){
        System.out.println("结果异常:" + throwable.getMessage() + "\r\n");
        return null;
    }
}

定义通知,实现Advice接口,这里我们实现MethodInterceptor接口,该接口底层继承自Advice接口

/**MyInterceptor.java**/
package com.sinbxeunha.josechan.aspect;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.stereotype.Component;

public class MyInterceptor implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        MyAspect aspect = new MyAspect();

        try{
            aspect.before(invocation);
            Object result = invocation.proceed();
            assert result != null;
            return aspect.after(result);
        }catch (Throwable throwable){
            return aspect.exceptionHandler(throwable);
        }
    }
}

创建代理对象

//工厂bean
ProxyFactoryBean bean = new ProxyFactoryBean();
//配置
AdvisedSupport config = new AdvisedSupport();
//目标类
Target target = new Target();
//通知
MyInterceptor interception = new MyInterceptor();
//设置目标类的接口
config.setInterfaces(new Class[]{TargetInterface.class});
//设置目标
config.setTarget(target);
//设置通知
config.addAdvice(interception);
//获得代理对象,链式调用 bean.获得工厂.配置工厂.获得代理对象
TargetInterface proxy = (TargetInterface) bean.getAopProxyFactory().createAopProxy(config).getProxy();

AspectJ

首先先定义一个切面类

/** AspectJAspect.java **/
package com.sinbxeunha.josechan.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.weaver.tools.JoinPointMatch;
import org.springframework.cglib.proxy.MethodProxy;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

//@Component
//@EnableAspectJAutoProxy
@Aspect
public class AspectJAspect {

    @Pointcut("execution(* com.sinbxeunha.josechan.service.*.*(..))")
    private void pointCut() {
    }

    //注解前置通知
    @Before("pointCut()")
    public Object before(JoinPoint joinPoint) {
        System.out.println("执行" + joinPoint.getSignature().toString() + "\r\n");
        return null;
    }

    //注解后置通知
    @AfterReturning(value = "pointCut()", returning = "result")
    public Object after(JoinPoint joinPoint, Object result) {
        assert result != null && result.toString() != null;
        System.out.println("执行结果:" + result.toString() + "\r\n");
        return result;
    }

    //注解抛出异常通知
    @AfterThrowing(value = "pointCut()", throwing = "throwable")
    public Object exceptionHandler(JoinPoint joinPoint, Throwable throwable) {
        System.out.println("结果异常:" + throwable.getMessage() + "\r\n");
        return null;
    }

    //注解最终通知
    @After("pointCut()")
    public Object afterAll(JoinPoint joinPoint) {
        return null;
    }

    //注解环绕通知,这个通知的增强内容相当于上面所有通知的并集
//    @Around("pointCut()")
    public Object around(ProceedingJoinPoint joinPoint) {
        try {
            before(joinPoint);
            Object result = joinPoint.proceed();
            assert result != null;
            return after(joinPoint, result);
        } catch (Throwable throwable) {
            return exceptionHandler(joinPoint, throwable);
        } finally {
            afterAll(joinPoint);
        }
    }
}

接下来通过工厂构造代理

// AspectJ
//目标类
Target target = new Target();
//切面类
AspectJAspect aspect = new AspectJAspect();
//代理工厂
AspectJProxyFactory factory = new AspectJProxyFactory();
factory.setTarget(target);
factory.setInterfaces(new Class[]{TargetInterface.class});
factory.addAspect(aspect);
//        //强制使用cglib
//        factory.setProxyTargetClass(true);
TargetInterface proxy = factory.getProxy();

通过spring容器实现自动AspectJ代理

要通过spring容器实现自动代理,需要将切面类解析道容器中,并且开启自动代理选项
只需要在切面类上增加两行注解:

/** AspectJAspect.java **/
//...省略

@Component
@EnableAspectJAutoProxy
////强制使用cglib
//@EnableAspectJAutoProxy(proxyTargetClass = true)
@Aspect
public class AspectJAspect {
//...省略
}

并且通过容器去获取目标类

//将目标类解析到容器中
//...省略
@Service
public class Target implements TargetInterface {
//...省略
//通过容器获取目标类
/** @var ApplicationContext applicationContext 容器实例 **/
Target proxy = applicationContext.getBean(Target.class);
上一篇 下一篇

猜你喜欢

热点阅读