使用Java实现AOP

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

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

1.Proxy代理

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

首先我们创建一个接口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分别输出了对应的信息。
利用Proxy实现AOP功能的总结如下:
  1. 目标对象必须实现接口
  2. 返回创建的代理对象
  3. 重写接口的invoke()方法
  4. 限制条件放在invoke()方法中
2.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的Java.lang.reflect.Method类的代理类,可以方便的实现对源对象方法的调用,如使用:Object o = methodProxy.invokeSuper(proxy, args);//虽然第一个参数是被代理对象,也不会出现死循环的问题。
实现AOP功能步骤如下所示:
  1. 引入相关jar文件
  2. 创建实体类
  3. 创建CGLib代理类
  4. 创建入口类进行测试
示例如下:
相关的jar包以及在创建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方法则是直接代理目标对象,不需要实现同一接口。



猜你喜欢

转载自blog.csdn.net/icarus_wang/article/details/51684526