1. 代理介绍
代理模式是Java开发中常用的设计模式,通过代理模式可以通过代理类实现与其它类的交互,使用者不感知具体的实现,只通过代理的方式得到想要的结果即可。代理类并不提供真正的服务,而是调用被代理类的相关方法实现真正的服务。
在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. 作用
- 实现单例模式,每次都会通过代理生成对象,不会影响元数据。在Spring中当需要使用Bean对象时,Bean对象会通过代理的方式将Bean生成一个代理类注入到容器中(Spring容器中存放的是代理类的引用,而不是元对象的引用),因此在容器中存放的对象是代理类,并不是元对象类,这也是为什么当开发者修改Bean对象时并不会影响元数据的原因。
- 程序运行时可以通过反射动态生成所需要的对象,无需提前编译生成。因此通过jdk动态代理和cglib代理可以实现对接口和类的全面代理实现。
- 通过代理可以实现对现有代码的增强,不管是接口还是类都可以在现有的基础上做增强,然后通过代理的方式执行我们增强的实现。
4. 执行
4.1 jdk代理执行链路
jdk:
-
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean(java.lang.String, org.springframework.beans.factory.support.RootBeanDefinition, java.lang.Object[])
-
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean
-
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBeanInstance
-
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#instantiateBean
-
org.springframework.beans.factory.support.SimpleInstantiationStrategy#instantiate(org.springframework.beans.factory.support.RootBeanDefinition, java.lang.String, org.springframework.beans.factory.BeanFactory)
-
org.springframework.beans.BeanUtils#instantiateClass(java.lang.reflect.Constructor, java.lang.Object...)
-
java.lang.reflect.Constructor#newInstance
4.2 cglib代理执行链路
cglib:
- org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean(java.lang.String, org.springframework.beans.factory.support.RootBeanDefinition, java.lang.Object[])
- org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean
- org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBeanInstance
- org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#instantiateBean
- org.springframework.beans.factory.support.SimpleInstantiationStrategy#instantiate(org.springframework.beans.factory.support.RootBeanDefinition, java.lang.String, org.springframework.beans.factory.BeanFactory)
- org.springframework.beans.factory.support.CglibSubclassingInstantiationStrategy.CglibSubclassCreator#instantiate
- org.springframework.beans.factory.support.CglibSubclassingInstantiationStrategy.CglibSubclassCreator#createEnhancedSubclass
5. 总结
通过Spring中创建Bean对象的过程梳理Spring是如何通过jdk动态代理和cglib动态代理实现生成代理Bean的。
在Spring容器中我们使用的对象都是已经被代理的类,它是在服务运行期间生成的代理Bean对象。
通过以上可以知道在Spring中使用到的代理模式有jdk动态代理和cglib动态代理。并且Spring中的AOP的切面实现也是通过代理的方式实现的。感兴趣的可以深入看一下AOP的部分,后续会再梳理。
以上就是自己关于Spring中代理的理解,个人能力有限,如有错误,欢迎评论私信指正!共同进步!