Spring中代理模式的使用源码分析

462 阅读4分钟

1. 代理介绍

代理模式是Java开发中常用的设计模式,通过代理模式可以通过代理类实现与其它类的交互,使用者不感知具体的实现,只通过代理的方式得到想要的结果即可。代理类并不提供真正的服务,而是调用被代理类的相关方法实现真正的服务。

image.png

在Spring中代理模式的使用在很多地方都体现,比如创建Bean对象时、AOP切面实现时等等,在Spring的实现中以JDK动态代理和CGLIB代理实现的两种方式,下面就从这两个实现方式梳理一下代理模式的逻辑以及Spring中调用代理的逻辑。

2. 使用

要了解Spring的实现,那么自己先以JDK代理和CGLIB代理写个例子,搞清楚这两种方式的实现异同,以及在基础例子的实现中,Spring是如何做的。

2.1 JDK代理实现

/**
* @author chenlingl
* @version 1.0
* @description 目标类
* @date 2023/1/18 15:02
*/
public interface UserDao {
    String query(String id);
}
/**
* @author chenlingl
* @version 1.0
* @description jdk实现接口的被代理类
* @date 2023/1/31 21:18
*/
public class UserService implements UserDao{
    @Override
    public String query(String id) {
        return "jdk代理结果:chentom";
    }
}
/**
 * @author chenlingl
 * @version 1.0
 * @description
 * @date 2023/1/17 16:35
 */
public class JdkProxy implements InvocationHandler{

    /**
     * 被代理类
     */
    private final Object object;

    public JdkProxy(Object object) {
        this.object = object;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        return method.invoke(object,args);
    }
}
/**
 * @author chenlingl
 * @version 1.0
 * @description 代理的工厂类
 * @date 2023/1/18 14:34
 */
public class JdkProxyFactory {

    protected UserDao newInstance(JdkProxy proxy) {
        return (UserDao)Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class[]{UserDao.class}, proxy);
    }

    public UserDao createInstance(UserDao proxy) {
        return newInstance(new JdkProxy(proxy));
    }
}
@SpringBootApplication
public class BootApplication {
    public static void main(String[] args) {
        SpringApplication.run(BootApplication.class,args);
        //jdk代理
        JdkProxyFactory jdkProxyFactory = new JdkProxyFactory();
        String query1 = jdkProxyFactory.createInstance().query("1");
        System.out.println(query1);
    }
}

2.2 CGLIB代理实现

/**
* @author chenlingl
* @version 1.0
* @description 目标类
* @date 2023/1/18 15:02
*/
public interface UserDao {
    String query(String id);
}
/**
* @author chenlingl
* @version 1.0
* @description cglib代理接口的实现类
* @date 2023/1/31 21:32
*/
public class CglibUserService implements UserDao {
    @Override
    public String query(String id) {
        return "cglib代理结果:陈汤姆";
    }
}
/**
 * @author chenlingl
 * @version 1.0
 * @description cgbli被代理类
 * @date 2023/1/17 16:35
 */
public class ProxyUser {
    public String queryCglib(String id) {
        Map<String,String> map = new HashMap<>();
        map.put("1","cglib代理结果:陈汤姆");
        map.put("2","cglib代理结果:chenTom");
        return map.get(id);
    }
}
/**
 * @author chenlingl
 * @version 1.0
 * @description cglib的方式将目标类创建一个代理类
 * @date 2023/1/17 16:35
 */
public class CglibProxy {

    public Object createProxy(Class<?> targetProxy, Object callback) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(targetProxy);
        enhancer.setCallback(new CglibCallback());
        return enhancer.create();
    }
}
/**
 * @author chenlingl
 * @version 1.0
 * @description 代理类的拦截器,如果执行代理类时,则会调用该拦截器执行
 * @date 2023/1/18 14:41
 */
public class CglibCallback implements MethodInterceptor {

    @Override
    public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        return methodProxy.invokeSuper(o,args);
    }
}
@SpringBootApplication
public class BootApplication {

    public static void main(String[] args) {
        CglibProxy cglibProxy = new CglibProxy();
        //cglib代理类
        ProxyUser proxyUser = (ProxyUser) cglibProxy.createProxy(ProxyUser.class, new CglibCallback());
        String query = proxyUser.queryCglib("1");
        System.out.println(query);
        //cglib代理接口
        UserDao proxy = (UserDao) cglibProxy.createProxy(CglibUserService.class, new CglibCallback());
        String query2 = proxy.query("2");
        System.out.println(query2);
    }
}

3. 作用

  1. 实现单例模式,每次都会通过代理生成对象,不会影响元数据。在Spring中当需要使用Bean对象时,Bean对象会通过代理的方式将Bean生成一个代理类注入到容器中(Spring容器中存放的是代理类的引用,而不是元对象的引用),因此在容器中存放的对象是代理类,并不是元对象类,这也是为什么当开发者修改Bean对象时并不会影响元数据的原因。
  2. 程序运行时可以通过反射动态生成所需要的对象,无需提前编译生成。因此通过jdk动态代理和cglib代理可以实现对接口和类的全面代理实现。
  3. 通过代理可以实现对现有代码的增强,不管是接口还是类都可以在现有的基础上做增强,然后通过代理的方式执行我们增强的实现。

4. 执行

4.1 jdk代理执行链路

jdk:

  1. org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean(java.lang.String, org.springframework.beans.factory.support.RootBeanDefinition, java.lang.Object[])

  2. org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean

  3. org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBeanInstance

  4. org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#instantiateBean

  5. org.springframework.beans.factory.support.SimpleInstantiationStrategy#instantiate(org.springframework.beans.factory.support.RootBeanDefinition, java.lang.String, org.springframework.beans.factory.BeanFactory)

  6. org.springframework.beans.BeanUtils#instantiateClass(java.lang.reflect.Constructor, java.lang.Object...)

  7. java.lang.reflect.Constructor#newInstance

4.2 cglib代理执行链路

cglib:

  1. org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean(java.lang.String, org.springframework.beans.factory.support.RootBeanDefinition, java.lang.Object[])
  2. org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean
  3. org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBeanInstance
  4. org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#instantiateBean
  5. org.springframework.beans.factory.support.SimpleInstantiationStrategy#instantiate(org.springframework.beans.factory.support.RootBeanDefinition, java.lang.String, org.springframework.beans.factory.BeanFactory)
  6. org.springframework.beans.factory.support.CglibSubclassingInstantiationStrategy.CglibSubclassCreator#instantiate
  7. org.springframework.beans.factory.support.CglibSubclassingInstantiationStrategy.CglibSubclassCreator#createEnhancedSubclass

5. 总结

通过Spring中创建Bean对象的过程梳理Spring是如何通过jdk动态代理和cglib动态代理实现生成代理Bean的。

在Spring容器中我们使用的对象都是已经被代理的类,它是在服务运行期间生成的代理Bean对象。

通过以上可以知道在Spring中使用到的代理模式有jdk动态代理和cglib动态代理。并且Spring中的AOP的切面实现也是通过代理的方式实现的。感兴趣的可以深入看一下AOP的部分,后续会再梳理。

以上就是自己关于Spring中代理的理解,个人能力有限,如有错误,欢迎评论私信指正!共同进步!