使用Java实现AOP

使用Java来实现AOP的功能,主要介绍两种实现方法

  1. Proxy代理方法
  2. CGLib方法

1.Proxy代理

采用Proxy类方法,其基本流程为:主函数-->代理-->目标对象 采用Proxy类方法,其基本流程为:主函数-->代理-->目标对象
对于Proxy类有一个使用前提:目标对象必须要实现接口 对于Proxy类有一个使用前提:目标对象必须要实现接口
利用Proxy实现AOP的主要步骤如下: 利用Proxy实现AOP的主要步骤如下:
  1. 创建接口
  2. 创建接口实现类
  3. 创建代理工厂类
接下来我们使用示例来演示 接下来我们使用示例来演示
需求:学生类具有姓名属性,并具有空参数的构造函数和带参数的构造函数,获取学生的姓名属性并打印。 需求:学生类具有姓名属性,并具有空参数的构造函数和带参数的构造函数,获取学生的姓名属性并打印。
但是假如学生没有姓名属性的话获取学生姓名会返回Null值,为了避免这种情况的发生我们就得使用AOP的编程技巧来对getName方法进行增强。 但是假如学生没有姓名属性的话获取学生姓名会返回Null值,为了避免这种情况的发生我们就得使用AOP的编程技巧来对getName方法进行增强。
首先我们创建一个接口StudengInterface
public interface StudentInterface {
    public void print();
}

接口中只有一个方法:print 接口中只有一个方法:print
接下来创建接口实现类StudentBean 接下来创建接口实现类StudentBean
public class StudentBean implements StudentInterface{
    private String name;
    public StudentBean() {
    }
    public StudentBean(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public void print() {
        System.out.println("Hello World!");
    }
}
类中具有一个String类型的属性name,并包含一个空参数的构造函数和带参数的构造函数。 类中具有一个String类型的属性name,并包含一个空参数的构造函数和带参数的构造函数。
接下来创建代理工厂类ProxyFactory 接下来创建代理工厂类ProxyFactory
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class ProxyFactory implements InvocationHandler{
    private Object stu;

    /**
    * 创建目标对象的实体类
    * @param stu 目标对象
    * @return 目标对象实体类
    */
    public Object createStudentProxy(Object stu){
        this.stu=stu;
        //返回目标对象实体类,第一个参数目标对象的类加载器,第二个参数是目标对象的接口对象,
        // 第三个参数是InvocationHandler默认对象。此方法会回调invoke方法
        return Proxy.newProxyInstance(stu.getClass().getClassLoader(),stu.getClass().getInterfaces(),this);

    }

    /**
    * 处理业务逻辑:
    * 当Student存在名字则直接打印“Hello World”
    * 将如Student的名称为空,则输出相关的信息。如“名称为空,代理类已经拦截”等,
    * 表明代理类已经起作用了。
    */
    public Object invoke(Object proxy, Method method, Object[] args) throws InvocationTargetException, IllegalAccessException {
        StudentBean s= (StudentBean) stu;
        Object object=null;
        if (s.getName()!=null){
            object=method.invoke(stu,args);
        }else {
            System.out.println("名称为空,代理类已经拦截");
        }
        return object;
    }
}
创建对应入口类来测试代理是否生效 首先我们创建一个接口StudengInterface public interface StudentInterface { public void print(); } 接口中只有一个方法:print 接下来创建接口实现类StudentBean public class StudentBean implements StudentInterface{ private String name; public StudentBean() { } public StudentBean(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } public void print() { System.out.println("Hello World!"); } } 类中具有一个String类型的属性name,并包含一个空参数的构造函数和带参数的构造函数。 接下来创建代理工厂类ProxyFactory import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class ProxyFactory implements InvocationHandler{ private Object stu; /** * 创建目标对象的实体类 * @param stu 目标对象 * @return 目标对象实体类 */ public Object createStudentProxy(Object stu){ this.stu=stu; //返回目标对象实体类,第一个参数目标对象的类加载器,第二个参数是目标对象的接口对象, // 第三个参数是InvocationHandler默认对象。此方法会回调invoke方法 return Proxy.newProxyInstance(stu.getClass().getClassLoader(),stu.getClass().getInterfaces(),this); } /** * 处理业务逻辑: * 当Student存在名字则直接打印“Hello World” * 将如Student的名称为空,则输出相关的信息。如“名称为空,代理类已经拦截”等, * 表明代理类已经起作用了。 */ public Object invoke(Object proxy, Method method, Object[] args) throws InvocationTargetException, IllegalAccessException { StudentBean s= (StudentBean) stu; Object object=null; if (s.getName()!=null){ object=method.invoke(stu,args); }else { System.out.println("名称为空,代理类已经拦截"); } return object; } } 创建对应入口类来测试代理是否生效
public class Main {
    public static void main(String[] args){
        StudentInterface s1=new StudentBean();
//        StudentInterface s1=new StudentBean("wang");
        ProxyFactory factory=new ProxyFactory();
        StudentInterface s2= (StudentInterface) factory.createStudentProxy(s1);
        s2.print();
    }
}
可以看到有名称的StudentBean和没有名称的StudentBean分别输出了对应的信息。 可以看到有名称的StudentBean和没有名称的StudentBean分别输出了对应的信息。
利用Proxy实现AOP功能的总结如下: 利用Proxy实现AOP功能的总结如下:
  1. 目标对象必须实现接口
  2. 返回创建的代理对象
  3. 重写接口的invoke()方法
  4. 限制条件放在invoke()方法中
2.CGLib方法 public class Main { public static void main(String[] args){ StudentInterface s1=new StudentBean(); // StudentInterface s1=new StudentBean("wang"); ProxyFactory factory=new ProxyFactory(); StudentInterface s2= (StudentInterface) factory.createStudentProxy(s1); s2.print(); } } 可以看到有名称的StudentBean和没有名称的StudentBean分别输出了对应的信息。 利用Proxy实现AOP功能的总结如下: 目标对象必须实现接口 返回创建的代理对象 重写接口的invoke()方法 限制条件放在invoke()方法中 2.CGLib方法
CGLib官网: CGLib官网:
CGlib简述 CGlib简述
           Cglib (Code Generation Library) 是一个优秀的动态代理框架, 他是一个强大的,高性能的,高质量的Code生成类库,他可以在运行期扩展Java类与实现Java接口。 它的底层使用ASM在内存中动态的生成被代理类的子类,使用CGLIB即使代理类没有实现任何接口也可以实现动态代理功能。CGLIB具有简单易用的特点,它的运行速度要远远快于JDK的Proxy动态代理。 Cglib (Code Generation Library) 是一个优秀的动态代理框架, 他是一个强大的,高性能的,高质量的Code生成类库,他可以在运行期扩展Java类与实现Java接口。 它的底层使用ASM在内存中动态的生成被代理类的子类,使用CGLIB即使代理类没有实现任何接口也可以实现动态代理功能。CGLIB具有简单易用的特点,它的运行速度要远远快于JDK的Proxy动态代理。
使用CGLIB需要导入以下两个jar文件: 使用CGLIB需要导入以下两个jar文件:
    asm.jar – CGLIB的底层实现
asm.jar – CGLIB的底层实现
    cglib.jar – CGLIB的核心jar包。
cglib.jar – CGLIB的核心jar包。

CGLIB的核心类:

    net.sf.cglib.proxy.Enhancer – 主要的增强类
net.sf.cglib.proxy.Enhancer – 主要的增强类
    net.sf.cglib.proxy.MethodInterceptor – 主要的方法拦截类,它是Callback接口的子接口,需要用户实现
    net.sf.cglib.proxy.MethodProxy – JDK的.lang.reflect.Method类的代理类,可以方便的实现对源对象方法的调用,如使用:Object o = methodProxy.invokeSuper(proxy, args);//虽然第一个参数是被代理对象,也不会出现死循环的问题。
net.sf.cglib.proxy.MethodProxy – JDK的.lang.reflect.Method类的代理类,可以方便的实现对源对象方法的调用,如使用:Object o = methodProxy.invokeSuper(proxy, args);//虽然第一个参数是被代理对象,也不会出现死循环的问题。
CGlib简述 Cglib (Code Generation Library) 是一个优秀的动态代理框架, 他是一个强大的,高性能的,高质量的Code生成类库,他可以在运行期扩展Java类与实现Java接口。 它的底层使用ASM在内存中动态的生成被代理类的子类,使用CGLIB即使代理类没有实现任何接口也可以实现动态代理功能。CGLIB具有简单易用的特点,它的运行速度要远远快于JDK的Proxy动态代理。 使用CGLIB需要导入以下两个jar文件: asm.jar – CGLIB的底层实现 cglib.jar – CGLIB的核心jar包。 CGLIB的核心类: net.sf.cglib.proxy.Enhancer – 主要的增强类 net.sf.cglib.proxy.MethodInterceptor – 主要的方法拦截类,它是Callback接口的子接口,需要用户实现 net.sf.cglib.proxy.MethodProxy – JDK的.lang.reflect.Method类的代理类,可以方便的实现对源对象方法的调用,如使用:Object o = methodProxy.invokeSuper(proxy, args);//虽然第一个参数是被代理对象,也不会出现死循环的问题。
实现AOP功能步骤如下所示: 实现AOP功能步骤如下所示:
  1. 引入相关jar文件
  2. 创建实体类
  3. 创建CGLib代理类
  4. 创建入口类进行测试
示例如下: 示例如下:
相关的jar包以及在创建Spring工程的时候已经加载到项目中去了, 相关的jar包以及在创建Spring工程的时候已经加载到项目中去了,
如何创建Spring项目请看: 如何创建Spring项目请看:
需求和上面的一样 需求和上面的一样
首先创建一个学生类StudentBean 首先创建一个学生类StudentBean
public class StudentBean{
    private String name;

    public StudentBean() {
    }

    public StudentBean(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void print() {
        System.out.println("Hello World!");
    }
}
接下来创建对应的CGLib代理工厂类CGLibProxyFactory

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

import java.lang.reflect.Method;

/**
* cglib代理工厂类
* 注意实现的接口类是cglib包下的MethodInterceptor
*/
public class CGLibProxyFactory implements MethodInterceptor {
    private Object object;
    /**
    * 创建代理类对象
    * @param object 被代理对象
    * @return 代理类对象
    */
    public  Object createStudent(Object object){
        this.object=object;
        //利用Enhancer来创建代理类
        Enhancer enhancer=new Enhancer();
        //为目标对象指定父类
        enhancer.setSuperclass(object.getClass());
        //设置回调函数
        enhancer.setCallback(this);
        //返回生成的代理类
        return enhancer.create();
    }

    /**
    * 业务处理逻辑代码
    * 利用到了java的反射
    * @param o
    * @param method
    * @param objects
    * @param methodProxy
    * @return 代理类对象
    * @throws Throwable
    */
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        StudentBean student=(StudentBean)object;
        Object result=null;
        if (student.getName()!=null){
            methodProxy.invoke(object,objects);//利用反射来执行相应的方法
        }else{
            System.out.println("该方法已被拦截!");
        }
        return result;
    }
}

创建对应的入口类来测试
public class Main {
    public static void main(String[] args){
        StudentBean student1
                = (StudentBean) new CGLibProxyFactory().createStudent(new StudentBean());
        StudentBean student2
                = (StudentBean) new CGLibProxyFactory().createStudent(new StudentBean("wang"));
        student1.print();
        student2.print();
    }
}
可以看到输出结果为: 可以看到输出结果为:
该方法已被拦截! 该方法已被拦截!
Hello World! Hello World!
总结: 总结:
可以看到Proxy代理方法和CGLib方法实现AOP的步骤基本相同,主要区别是: 可以看到Proxy代理方法和CGLib方法实现AOP的步骤基本相同,主要区别是:
使用Proxy代理类,他创建出来的目标对象和代理对象都必须实现相同的接口 使用Proxy代理类,他创建出来的目标对象和代理对象都必须实现相同的接口。
而CGLib方法则是直接代理目标对象,不需要实现同一接口。 而CGLib方法则是直接代理目标对象,不需要实现同一接口。


CGLib官网: CGlib简述 Cglib (Code Generation Library) 是一个优秀的动态代理框架, 他是一个强大的,高性能的,高质量的Code生成类库,他可以在运行期扩展Java类与实现Java接口。 它的底层使用ASM在内存中动态的生成被代理类的子类,使用CGLIB即使代理类没有实现任何接口也可以实现动态代理功能。CGLIB具有简单易用的特点,它的运行速度要远远快于JDK的Proxy动态代理。 使用CGLIB需要导入以下两个jar文件: asm.jar – CGLIB的底层实现 cglib.jar – CGLIB的核心jar包。 CGLIB的核心类: net.sf.cglib.proxy.Enhancer – 主要的增强类 net.sf.cglib.proxy.MethodInterceptor – 主要的方法拦截类,它是Callback接口的子接口,需要用户实现 net.sf.cglib.proxy.MethodProxy – JDK的.lang.reflect.Method类的代理类,可以方便的实现对源对象方法的调用,如使用:Object o = methodProxy.invokeSuper(proxy, args);//虽然第一个参数是被代理对象,也不会出现死循环的问题。 实现AOP功能步骤如下所示: 引入相关jar文件 创建实体类 创建CGLib代理类 创建入口类进行测试 示例如下: 相关的jar包以及在创建Spring工程的时候已经加载到项目中去了, 如何创建Spring项目请看: 需求和上面的一样 首先创建一个学生类StudentBean public class StudentBean{ private String name; public StudentBean() { } public StudentBean(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } public void print() { System.out.println("Hello World!"); } } 接下来创建对应的CGLib代理工厂类CGLibProxyFactory import org.springframework.cglib.proxy.Enhancer; import org.springframework.cglib.proxy.MethodInterceptor; import org.springframework.cglib.proxy.MethodProxy; import java.lang.reflect.Method; /** * cglib代理工厂类 * 注意实现的接口类是cglib包下的MethodInterceptor */ public class CGLibProxyFactory implements MethodInterceptor { private Object object; /** * 创建代理类对象 * @param object 被代理对象 * @return 代理类对象 */ public Object createStudent(Object object){ this.object=object; //利用Enhancer来创建代理类 Enhancer enhancer=new Enhancer(); //为目标对象指定父类 enhancer.setSuperclass(object.getClass()); //设置回调函数 enhancer.setCallback(this); //返回生成的代理类 return enhancer.create(); } /** * 业务处理逻辑代码 * 利用到了java的反射 * @param o * @param method * @param objects * @param methodProxy * @return 代理类对象 * @throws Throwable */ public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { StudentBean student=(StudentBean)object; Object result=null; if (student.getName()!=null){ methodProxy.invoke(object,objects);//利用反射来执行相应的方法 }else{ System.out.println("该方法已被拦截!"); } return result; } } 创建对应的入口类来测试 public class Main { public static void main(String[] args){ StudentBean student1 = (StudentBean) new CGLibProxyFactory().createStudent(new StudentBean()); StudentBean student2 = (StudentBean) new CGLibProxyFactory().createStudent(new StudentBean("wang")); student1.print(); student2.print(); } } 可以看到输出结果为: 该方法已被拦截! Hello World! 总结: 可以看到Proxy代理方法和CGLib方法实现AOP的步骤基本相同,主要区别是: 使用Proxy代理类,他创建出来的目标对象和代理对象都必须实现相同的接口。 而CGLib方法则是直接代理目标对象,不需要实现同一接口。

经验分享 程序员 微信小程序 职场和发展