SpringAOP编程实现

我百度过AOP的实现方式好像有四种

  • 第一种 静态AOP:在编译期,切面直接以字节码的形式编译到目标字节码文件中
    优点:被织入的类性能不受影响。
    缺点:不够灵活

  • 第二种 动态AOP(JDK动态代理) :在运行期间,目标类加载后,为接口动态生成代理类,将切面植入到代理类中。
    Java从1.3引入动态代理,实现原理是为被代理的业务接口生成代理类,将AOP逻辑写入到代理类中,在运行时动态织入AOP,使用反射执行织入的逻辑。主要实现方式依赖java.lang.reflect包下的InvocationHandler和Proxy类。
    优点:java标准库原生支持,使用简单,无需引用额外的包。相对于静态AOP更灵活
    缺点:带代理的类必须是接口,灵活性受到一些限制,使用反射会影响一些性能。

  • 3.动态代码字节生成:在运行期间,目标类加载后,动态构建字节码文件生成目标类的子类,将切面逻辑加入到子类中。
    CGLib是动态代码字节生成的实现,它封装字节码工具Asm,原理是在运行期间,目标字节码加载后,生成目标的子类,将切面逻辑加入到子类中,所以使用Cglib实现AOP不需要的接口。
    优点:没有接口也能织入,灵活性高
    缺点:扩展类的实例方法为final时,则无法进行织入

  • 4 自定义类加载器:在运行前,目标加载前,将切面逻辑加到目标字节码中.。
    可以考虑javassist来实现,javassist是一个编辑字节码的框架,可以让你很简单的操作字节码。他可以在运行期间定义或修改Class。使用Javassist实现AOP的原理是在字节码加载前直接修改需要切入的方法。
    有点:可以对绝大部分类织入。
    缺点:如果用到了其他类加载器,则这些类将不被织入

本次写了动态JDK代理和字节码生成子类的方式实现AOP

贴类图

在这里插入图片描述
其中JDK的类是JDK动态代理实现的,CGLib的类是动态字节码生成实现的

现在开始实现,首先创建接口以及实现类(由于JDK动态代理只能代理接口,不能代理实例类,但是CGLib全都能代理,所以得创建一个借口用于测试JDK动态代理)

HelloAOP

package com.spring.aop.example;

/**
 * 被代理的接口,基于jdk动态代理
 */
public interface HelloAOP {

    //被动态的目标方法
    public void show(String name);

}

HelloAOPImpl

package com.spring.aop.example;

/**
 * aop的接口实现类
 */
public class HelloAOPImpl implements HelloAOP {
    @Override
    public void show(String name) {
        System.out.println("===========hello,"+name+"=============");
    }
}

创建完毕后,先写JDK的动态代理实现方式(代码很简单,我就不一一解释了,看注释就能看懂)

package com.spring.aop.example.dynamic;

import com.spring.aop.example.HelloAOP;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * 代理目标为接口的JDK动态代理demo
 * aop:aspectj-autoProxy proxy-target-class = false
 */
public class JDKDynamicProxy implements InvocationHandler {

    //被代理的目标对象;
    private HelloAOP helloAOP;

    public JDKDynamicProxy(HelloAOP helloAOP){
        this.helloAOP=helloAOP;
    }

    @Override   //proxy 代理对象  method 目标所有的方法, 方法参数
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //动态代理,前置增强处理
        before();
        //代理方法执行,代理的目标实例,方法执行参数
        Object result = method.invoke(helloAOP,args);
        //动态代理,后置增强
        after();
        return result;
    }

    //生成代理对象并返回,
    public HelloAOP getProxy(){
        //生成代理对象,并返回
        return (HelloAOP) Proxy.newProxyInstance(
                //加载委托类
                this.helloAOP.getClass().getClassLoader(),
                //获取委托类里所有方法
                this.helloAOP.getClass().getInterfaces(),
                //代理对象执行的方法体
                this
        );
    }

    public void before(){
        System.out.println("JDK前置增强");
    }
    public void after(){
        System.out.println("JDK后置增加");
    }
}

接着创建一个通用的封装过后的JDK动态代理类

package com.spring.aop.example.dynamic;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * 封装通用的JDK动态代理类
 *
 * 基于单例模式封装通用的jdk动态代理类
 */
public class JDKDynamicProxyBuild implements InvocationHandler {

    //目标委托实例
    private Object target;

    /**
     * 构造注入委托实例
     * @param target
     */
    public JDKDynamicProxyBuild(Object target){
        this.target=target;
    }

    /**
     * 生成动态代理类
     * @param obj
     * @param <T>
     * @return
     */
    public <T> T getProxy(Class<T> obj){
        return (T) Proxy.newProxyInstance(
                target.getClass().getClassLoader(), //获取加载委托类
                target.getClass().getInterfaces(),  //获得委托类需要实现的所有接口
                this    //执行动态代理方法
        );
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        before();
        Object result = method.invoke(target,args);
        after();
        return result;
    }

    public void before(){
        System.out.println("JDK动态代理封装----前置增强");
    }
    public void after(){
        System.out.println("JDK动态代理封装----后置增强");
    }

}

就这样JDK动态代理实现AOP就已经写完了,感觉不是很难,接下来写CGLib的实现方式

同上面一样,创建一个CGLib动态代理类。
package com.spring.aop.example.dynamic;

import com.spring.aop.example.HelloAOPImpl;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * 代理任意目标类的CGLIB动态代理DEMO
 * CGLIB是一个强大、高性能的字节码生成库,它用于在运行是拓展,java类的实现接口;
 * 本质上他是通过动态的生成了一个子类去覆盖所要代理的类(非final修饰的类和方法)。
 */
public class CGLibDynamicProxy implements MethodInterceptor {

    //代理目标实例
    private HelloAOPImpl helloAOPImpl;

    //创建代理实例并返回
    public Object getInstance(HelloAOPImpl helloAOPImpl){
        this.helloAOPImpl=helloAOPImpl;
        /**
         * Enhancer是一个非常重要的类,它允许为非接口类型创建一个java代理,
         * Enhancer动态的创建给定类的子类,并且拦截代理类的所有方法。
         * 和jdk动态代理不一样的是不管是接口还是类他都能正常工作。
         * 而jdk动态代理,只能代理接口
         */
        //Enhancer动态代理对象
        Enhancer enhancer = new Enhancer();

        //给动态代理对象设置指定的代理类
        enhancer.setSuperclass(HelloAOPImpl.class);
        //设置回调
        enhancer.setCallback(this);
        //创建并返回的代理类的实例
        return enhancer.create();
    }

    @Override   //obj 代理对象, method 委托类方法,arg 方法参数,methodproxy代理方法的methodProxy对象
    public Object intercept(Object obj, Method method, Object[] arg, MethodProxy methodProxy) throws Throwable {
        //前置增强
        before();
        //通过代理对象调用父类的方法
        Object result = methodProxy.invokeSuper(obj,arg);
        //后置增强
        after();
        return result;
    }

    public void before(){
        System.out.println("CGLIB动态代理------前置增强");
    }

    public void after(){
        System.out.println("CGLIB动态代理------后置增强");
    }
}

在创建一个通用的封装过后的类

package com.spring.aop.example.dynamic;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

/**
 * 封装通用的CGLIB动态代理类
 */
public class CGLIBDynamicProxyBuild implements MethodInterceptor {


    //代理类实例
    private static CGLIBDynamicProxyBuild  dynamicProxyBuild = new CGLIBDynamicProxyBuild();

    /**
     * 私有的构造,外界无法创建动态代理类实例
     */
    private CGLIBDynamicProxyBuild(){ }

    /**
     * 单例模式,饿汉模式:类加载速度慢,获取对象速度快,线程安全,不能延迟加载
     * @return
     */
    public static CGLIBDynamicProxyBuild getInstance(){
        return dynamicProxyBuild;
    }
    //创建动态代理类实例
    @SuppressWarnings("unchecked")
    public <T> T getProxy(Class<T> cls){
        return (T) Enhancer.create(cls,this);
    }

    @Override
    public Object intercept(Object target, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        before();
        Object result = methodProxy.invokeSuper(target,args);
        after();
        return result;
    }

    public void before(){
        System.out.println("CGLIB动态代理封装----前置增强");
    }
    public void after(){
        System.out.println("CGLIB动态代理封装----后置增强");
    }


}

这样就写完了,其中织入过程已经用代码写的很清楚了,直接测试就行了 。

package com.spring.aop;

import com.spring.aop.example.HelloAOP;
import com.spring.aop.example.HelloAOPImpl;
import com.spring.aop.example.dynamic.CGLIBDynamicProxyBuild;
import com.spring.aop.example.dynamic.CGLibDynamicProxy;
import com.spring.aop.example.dynamic.JDKDynamicProxy;
import com.spring.aop.example.dynamic.JDKDynamicProxyBuild;

public class Test {

    @SuppressWarnings(value = "unchecked")
    public static void main(String[] args) {

        //创建helloAop对象,由于JDK只能代理接口,所有需要用实现类实现接口的方式创建对象
        HelloAOP helloAOP = new HelloAOPImpl();
        //生成代理类,代理的目标对象为HelloAop,生成它的代理类
        JDKDynamicProxy proxy = new JDKDynamicProxy(helloAOP);
        //代理类调用目标代理对象的方法,并传入参数
        proxy.getProxy().show("张三");
        System.out.println();

        //创建委托类实例
        HelloAOPImpl helloAOPImpl = new HelloAOPImpl();
        //创建CGLib动态代理实例
        CGLibDynamicProxy proxy1 = new CGLibDynamicProxy();
        //动态创建helloaopimpl动态代理的代理类,
        // CGLIB创建代理类的原理是创建一个以委托类作为目标对象的子类,
        // 并重写父类的所有非fanil方法,子类会拦截父类的非final所有方法,顺便织入横切逻辑
        //这里创建cglibProxy代理对象作为 helloAOPImpl类的子类,并拦截父类的所有方法
        Object cglibProxy = proxy1.getInstance(helloAOPImpl);
        //代理类向上转型为父类
        HelloAOPImpl realProxy = (HelloAOPImpl) cglibProxy;
        //子类重写父类的方法再向上转型为父类,所以父类调用的就是子类的方法,而这个方法已经被增强了
        realProxy.show("李四");

        System.out.println();

        //创建代理对象
        HelloAOP helloAOP1 = new HelloAOPImpl();
        //创建代理实例
        JDKDynamicProxyBuild rebuild = new JDKDynamicProxyBuild(helloAOP1);
        //JDK动态生成代理目标对象的委托类,
        HelloAOP proxy2 = rebuild.getProxy(HelloAOP.class);
        proxy2.show("王五");

        System.out.println();

        //创建委托类实例
        CGLIBDynamicProxyBuild rebuild2 = CGLIBDynamicProxyBuild.getInstance();
        //生成代理类的委托类
        HelloAOPImpl helloAOPImpl2 =  rebuild2.getProxy(HelloAOPImpl.class);
        //调用方法
        helloAOPImpl2.show("赵六");

    }


}

测试结果

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值