Spring-AOP 分享

时间:2021-08-04
本文章向大家介绍Spring-AOP 分享,主要包括Spring-AOP 分享使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

一、spring aop简介与应用

  1. Spring AOP的几个概念
  • 切面(Aspect):切面就是一个关注点的模块化,如事务管理、日志管理、权限管理等;
  • 连接点(Joinpoint):程序执行时的某个特定的点,在Spring中就是一个方法的执行;
  • 增强(Advice):增强就是在切面的某个连接点上执行的操作,也就是事务管理、日志管理等;
  • 切入点(Pointcut):切入点就是描述某一类选定的连接点,也就是指定某一类要织入通知的方法;
  • 织入(Weaving):将Aspect加入到程序代码的过程,对于SpringAOP,由ProxyFactory或者ProxyFactoryBean负责织入动作。
  • 目标对象(Target):就是被AOP动态代理的目标对象;
  1. 增强类型
  • 前置增强(@Before):在目标方法执行前实施增强。
  • 后置增强(@AfterReturning,@After):AfterReturning在目标方法正常执行后实施增强,如果方法抛出异常不会执行;@After增强的方法则无论是否有异常都会执行,类似finally方法。类似于finally代码块,只要应用了无论什么情况下都会执行
  • 环绕增强(@Around):在目标方法执行前后实施增强。直接使用了AOP联盟定义的接口。
  • 异常抛出增强(@AfterThrowing):在目标方法抛出异常后实施增强。
  • 引介增强():在目标类中添加一些新的方法和属性,连接点是类级别的而非方法级别的。
  1. 切点表达式
    | 内容项 | 示例 |
    | ------------------------------- | ----------------------------------------------- |
    | 任意公共方法的执行 | execution(public * (..)) |
    | 任何一个以“set”开始的方法的执行 | execution(
    set(..)) |
    | DemoService接口的任意方法的执行 | execution(
    com.demo.service.DemoService.(..)) |
    | 定义在service包里的任意方法的执行 | execution(
    com.demo.service..(..)) |
    | 定义在service包和所有子包里的任意类的任意方法的执行 | execution(* com.demo.service...(..)) |
    | 定义在demo包和所有子包里的DemoDao类的任意方法的执行 | execution(* com.demo..DemoDao.*(..)) |
    二、动态代理介绍
  2. jdk动态代理
    JDK动态代理通过反射来接收被代理的类,并且要求被代理的类必须实现一个接口。JDK动态代理的核心是InvocationHandler接口和Proxy类
    接口
    /**
  • @Classname InterfaceBean
  • @Date 2021/8/4 10:53 上午
  • @Created by jinhanping
    /
    public interface InterfaceBean {
    String sayHello(String arg);
    }
    实现类
    /
    *
  • @Classname InterfaceBeanImpl
  • @Date 2021/8/4 10:52 上午
  • @Created by jinhanping
    */
    public class InterfaceBeanImpl implements InterfaceBean {
    @Override
    public String sayHello(String arg) {
    System.out.println("InterfaceBeanImpl 你好 "+arg);
    return "OK";
    }
    }

JDK 动态代理
/**

  • @Classname JdkDynamicProxy

  • @Date 2021/8/4 10:55 上午

  • @Created by jinhanping
    */
    @Slf4j
    public class JdkDynamicProxy implements InvocationHandler {
    private InterfaceBean target;

    public JdkDynamicProxy(InterfaceBean target) {
    this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    if ("sayHello".equals(method.getName())) {
    log.info("JDK动态代理");
    }
    return method.invoke(target, args);
    }
    }

测试
public static void main(String[] args) {
InterfaceBean bean = (InterfaceBean) Proxy.newProxyInstance(
InterfaceBean.class.getClassLoader(),
new Class<?>[] {InterfaceBean.class},
new JdkDynamicProxy(new InterfaceBeanImpl())
);
bean.sayHello("java six six six");

}
  1. cglib动态代理
    CGLIB(Code Generation Library),是一个代码生成的类库,可以在运行时动态的生成某个类的子类,注意,CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记为final,那么它是无法使用CGLIB做动态代理的,诸如private的方法也是不可以作为切面的。
    // 目标类
    public class ClassBean {

    public String print(String something) {
    return something;
    }

}

// cglib代理
public class CglibProxy implements MethodInterceptor {

@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
    Logger logger = LoggerFactory.getLogger(CglibProxy.class);
    logger.info("cglib proxy is applyed");
    return proxy.invokeSuper(obj, args);
}

}

// 测试类
public class ProxyTest {

@Test
public void testCglibProxy() {
    Enhancer enhancer = new Enhancer();
    enhancer.setSuperclass(ClassBean.class);
    enhancer.setCallback(new CglibProxy());

    ClassBean bean = (ClassBean)enhancer.create();
    bean.print("double six six six");
}

}

上述代码中,我们通过CGLIB的Enhancer来指定要代理的目标对象、实际处理代理逻辑的对象,最终通过调用create()方法得到代理对象,对这个对象所有非final方法的调用都会转发给MethodInterceptor.intercept()方法,在intercept()方法里我们可以加入任何逻辑,比如修改方法参数,加入日志功能、安全检查功能等;通过调用MethodProxy.invokeSuper()方法,我们将调用转发给原始对象。

  1. 总结
    Jdk动态代理获取的对象,实际是Proxy子类,且实现了代理类接口;
    Cglib动态代理获取的代理对象,是代理类的子类,

原文地址:https://www.cnblogs.com/jphjava/p/15098199.html