Spring AOP系列之代理创建

Spring Boot AOP系列之动态代理创建


序言:在本文中,我会讲到Spring中如何创建动态代理,如何利用jdk或者cglib来创建动态代理,但是同时,我也会提及如何手动创建代理,这将有助于我们了解动态代理的原理。我们先来讲讲如何手动创建吧。

一、 手动创建之jdk动态代理

1、 jdk动态代理是基于接口的,所以必须要写一个接口,以及实现类,然后还需要写一个类来实现InvocationHandler类,

接口如下

public interface Helloworld {
     
    void sayHello();
}

实现类如下:

public class HelloworldImpl implements HelloWorld {
     
    public void sayHello() {
        System.out.print("hello world");
    }
}

拦截类如下:

public class MyInvocationHandler implements InvocationHandler{
     
    private Object target;
    public MyInvocationHandler(Object target) {
        this.target=target;
    }
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("method :"+ method.getName()+" is invoked!");
        return method.invoke(target,args);
    }
}

测试如下:

public class JDKProxyTest {
     
    public static void main(String[]args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
       //重要的是这里的newProxyInstance方法,后面博文讲原理的时候会讲到为什么会植入切面的
        HelloWorld helloWorld=(HelloWorld)Proxy.
                 newProxyInstance(JDKProxyTest.class.getClassLoader(),
                        new Class[]{HelloWorld.class},
                        new MyInvocationHandler(new HelloworldImpl()));
        helloWorld.sayHello();
    }

}
2、这里先教大家怎么做,以后教大家原理,现在依葫芦画瓢就行

二、手动创建之CGLIB代理

1、cglib代理和jdk代理目的差不多,但是cglib代理不仅可以代理接口,还可以代理类,比jdk代理作用 范围更加广泛一些,cglib代理借助了ASM这个非常强大的Java字节码生成框架
2、demo如下

接口:

public interface Subject {
         
   public void request();  
}

实现:

public class RealSubject implements Subject{
         
   public void request(){    
       System.out.println("From real subject.");    
   }    
}

处理类,也叫回调方法:

//实现了InvocationHandler,很重要
public class DynamicSubjectHandler implements InvocationHandler    
{
         
    private Object obj;//这是动态代理的好处,被封装的对象是Object类型,接受任意类型的对象    

    public DynamicSubject()    
    {    
    }    

    public DynamicSubject(Object obj)    
    {    
        this.obj = obj;    
    }    

    //这个方法不是我们显示的去调用    
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable    
    {    
        System.out.println("before calling " + method);    

        method.invoke(obj, args);    

        System.out.println("after calling " + method);    

        return null;    
    }    

}    

Test方法:

public class Client{
     
    public static void main(String[] args){
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(RealSubject.class);//继承被代理的那个类
        enhancer.setCallback(new DynamicSubjectHandler())//设置回调类
        RealSubject realSubject = (RealSubject)enhancer.create();//创建代理对象
        realSubject.request();
    }
}
//PS: 这段代码是我手敲的,大家粘贴的时候注意一下哈
2、执行main方法之后,DynamicSubjectHandler 中的invoke方法会被显式调用,打印出信息,原理后面我会介绍,详情关注下篇博文。

三、Spring boot创建之JDK动态代理

事实上,spring对于代理的类的创建选用何种方法是有规律可寻的,详细可看一下源代码,如下:

spring在创建代理的时候,会调用DefaultAopProxyFactory里面的createAopProxy方法,这个方法会取判断是使用jdk动态代理还是cglib代理。第一个参数,config.isOptimize(),这个方法是一个配置的,用于判断创建代理是否乐观(是否会经常改动),默认配置为false,第二个参数是不是目标代理类。第三个参数,hasNoUserSuppliedProxyInterfaces()这个方法,判断代理类的AdviseSupport处理类是不是只会指定SpringProxy这个接口,一般会返回true。当这些条件都不满足的时候,spring 默认走jdk动态代理。当满足这些条件中某一个的时候,去判断是不是接口或者已经是代理类,如果是接口或者已经是代理类的时候,就去走jdk动态代理,否者走cglib代理

OK,讲清楚了spring选择动态代理的原因之后,我们来看看怎么指定jdk动态代理。

Spring boot配置jdk动态代理很简单,只需要在Spring boot配置文件中配置

spring.aop.proxy-target-class=false

然后自己写代理类的时候注意是接口就完毕啦。

四、Spring boot创建之Cglib代理

同理,spring boot创建Cglib代理也很简单,直接配置

spring.aop.proxy-target-class=true

就可以强制使用cglib代理

下篇博文介绍原理哈

你可能感兴趣的:(java,spring,spring-boot,动态代理,aop,jdk动态代理)