Spring/Boot/Cloud系列知识(4)——代理模式(下)
=============================================
(接上文《Spring/Boot/Cloud系列知识(3)——代理模式(中)》)
3.3 Proxy.newProxyInstance内部如何完成工作的
我们来看看org.mockito.cglib.proxy.Proxy.newProxyInstance这个方法内部的代码:
public class Proxy implements Serializable {
......
// 这个常量BAD_OBJECT_METHOD_FILTER(代理选择器)的设定,等一下会用到
// 实际上代码也清楚,一般情况下执行第0个代理器,如果是代理执行java.lang.Object中的方法
// 且这些方法又不是hashCode()、equals()、toString(),则执行第1个代理器
private static final CallbackFilter BAD_OBJECT_METHOD_FILTER = new CallbackFilter() {
public int accept(Method method) {
if (method.getDeclaringClass().getName().equals("java.lang.Object")) {
String name = method.getName();
if (!(name.equals("hashCode") ||
name.equals("equals") ||
name.equals("toString"))) {
return 1;
}
}
return 0;
}
};
......
// private for security of isProxyClass
private static class ProxyImpl extends Proxy {
protected ProxyImpl(InvocationHandler h) {
super(h);
}
}
......
// 该方法中使用了Cglib中对ASM freamework的封装,动态创建一个class定义
public static Class getProxyClass(ClassLoader loader, Class[] interfaces) {
Enhancer e = new Enhancer();
// 为这个class设置一个父类,这个父类名叫ProxyImpl,其中定义了一个构造函数
// 那个构造函数需要传入个代理器对象
e.setSuperclass(ProxyImpl.class);
// 然后为这个class设置接口,请注意,可以设置多个接口哦
e.setInterfaces(interfaces);
// 为这个动态class设置代理器类型,设定了这个方法就应该使用CallbackFilter设定代理选择器(过滤器)
e.setCallbackTypes(new Class[]{
InvocationHandler.class,
NoOp.class,
});
// 这个我们使用了Proxy中,在前文定义好的BAD_OBJECT_METHOD_FILTER常量,请参见
//
e.setCallbackFilter(BAD_OBJECT_METHOD_FILTER);
e.setUseFactory(false);
// 最后创建这个动态class(注意是创建class,并不是这个class的实例)
return e.createClass();
}
......
// newProxyInstance方法中实际上就是两句话,重要的代码都在getProxyClass这个方法中。
public static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h) {
try {
// 该方法用来动态创建一个class,请参考方法中的内容
Class clazz = getProxyClass(loader, interfaces);
// 很显然,通过以上方法我们拿到了一个动态class,这个class有三个重要特点,
// 1、这个class有一个带有参数的构造函数,这个参数就是需要我们传入代理器接口的一个实现实例。
// 2、这个class实现了我们需要它实现的一个或者多个接口——没有实现代码,但是有这样的类结构
// 3、这个class设定了两个代理器,通常执行第0个代理器,就是我们传入的InvocationHandler h对象
// 另外,如果是代理执行java.lang.Object中的方法
// 且这些方法又不是hashCode()、equals()、toString(),则执行第1个代理器
//
// 接着,我们执行第二句代码,这句代码初始化一个这个动态类的示例,并传入代理器实例对象
return clazz.getConstructor(new Class[]{ InvocationHandler.class }).newInstance(new Object[]{ h });
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
throw new CodeGenerationException(e);
}
}
......
}
要阅读本小节以上代码片段,请从上篇文章中newProxyInstance()方法开始看。
4 Cglib和JDK动态代理在Spring中的应用
4.1、再次说明JDK动态代理的实例
Spring中使用JDK动态代理的情况已将在前文中介绍过一次(请参见前文《Spring/Boot/Cloud系列知识(3)——代理模式(中)》),这里再举一个实际应用——Spring Data JPA组件。我们通过实现了Java JPA规范的Hibernate组件,定义了一个AgentRepository接口,注意这个接口没有任何实现,只有接口、接口方法和接口方法注解上的HQL/SQL操作语句(如果您的接口方法遵循了JPA规范标准定义,甚至没有操作语句的注解也成)。接着我们在某个Service中依赖注入这个AgentRepository接口对象。
- 以下是AgentRepository接口的定义。请注意,这个接口遵循JPA规范,其下并没有任何实现类:
@Repository("agentRepository")
public interface AgentRepository extends JpaRepository<AgentEntity, String>, JpaSpecificationExecutor<AgentEntity> {
AgentEntity findByAccountAndStatus(String account , UseStatus status);
AgentEntity findByAccount(String account);
@Modifying
@Query(value="insert into role_agent(agent_id , role_id) value (:agentId , '2bb')" , nativeQuery=true)
void bindAgentRole(@Param("agentId") String agentId);
}
- 接着我们在其它代码中,注入这个对象,并通过debug模式观察AgentRepository接口实例的对象引用情况(关于Spring-data-JPA这个组件本专题后续文章还会详细讲解):
4.2、Cglib代理在Spring中的应用
(1)Cglib的封装
实际上Spring组件并没有直接使用Cglib的原生类/工具,而是通过Spring Core组件对Cglib组件进行了封装/重写,在Spring Core组件中的org.springframework.cglib包中:
在介绍Cglib在Spring生态中的具体应用前,我们先来看看在以上的代码示例中Cglib代理的应用位置:
通过MyService接口实例在Debug模式下显示的内容可以看到,myService是一个Spring通过Cglib组件动态生成的代理实例,这里有7个代理器对象,负责在不同的方法被调用时进行代理。
(2)Cglib的代理器原理
Spring AOP组件中,默认使用Cglib动态代理。它对Cglib动态代理的支持,主要由Spring-cor组件提供,而Spring AOP组件依赖于Spring Core组件。前者Spring AOP组件中的org.springframework.aop.framework.DefaultAopProxyFactory类将决定和生成具体的代理器——JdkDynamicAopProxy或者ObjenesisCglibAopProxy(这是CglibAopProxy类的子类)。我们来看看org.springframework.aop.framework.CglibAopProxy这个类中的一些重要代码——主要是其中如何组装各种代理器的:
public Object getProxy(ClassLoader classLoader) {
......
// 这是Spring Core中封装的org.springframework.cglib.proxy.Enhancer类
// 可见Spring aop组件中依赖于spring core组件。
// Configure CGLIB Enhancer...
Enhancer enhancer = createEnhancer();
// ========以下代码用于动态生成被代理的proxySuperClass的代理类
if (classLoader != null) {
enhancer.setClassLoader(classLoader);
if (classLoader instanceof SmartClassLoader &&
((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
enhancer.setUseCache(false);
}
}
enhancer.setSuperclass(proxySuperClass);
enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
enhancer.setStrategy(new ClassLoaderAwareUndeclaredThrowableStrategy(classLoader));
// 这句代码所涉及的方法使我们需要侧重阅读的代码
// 其中涉及到如何获取多个代理器的过程
Callback[] callbacks = getCallbacks(rootClass);
Class<?>[] types = new Class<?>[callbacks.length];
for (int x = 0; x < types.length; x++) {
types[x] = callbacks[x].getClass();
}
// fixedInterceptorMap only populated at this point, after getCallbacks call above
enhancer.setCallbackFilter(new ProxyCallbackFilter(this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
enhancer.setCallbackTypes(types);
// Generate the proxy class and create a proxy instance.
return createProxyClassAndInstance(enhancer, callbacks);
......
}
private Callback[] getCallbacks(Class<?> rootClass) throws Exception {
// Parameters used for optimisation choices...
// advised是AOP配置信息的一个对象(AdvisedSupport extends ProxyConfig implements Advised)
// 从内部代码看,exposeProxy属性和frozen属性来自于它的父类ProxyConfig,默认值都为false
boolean exposeProxy = this.advised.isExposeProxy();
boolean isFrozen = this.advised.isFrozen();
// targetSource是org.springframework.aop.TargetSource接口的一个实现,
// 它描述了被代理/被切面的实际对象。其下有很多实现,包括但不限于:PrototypeTargetSource、ThreadLocalTargetSource、
// EmptyTargetSource、SimpleBeanTargetSource、CommonsPool2TargetSource等
// 视不同的代理目标、环境配置,使用的实现类不一样。
// 其中SingletonTargetSource类是TargetSourcede的默认实现,当被代理的目标是来自于Spring IOC容器的简单对象时,就使用此代理类实现代理
// SingletonTargetSource类实例中的isStatic属性,默认返回true
boolean isStatic = this.advised.getTargetSource().isStatic();
......
// 这个数组是实现了Callback接口的多个对象,就是在上图中看到的7个代理器对象。
// 其中aopInterceptor对象是DynamicAdvisedInterceptor代理器的实现
Callback[] mainCallbacks = new Callback[] {
aopInterceptor, // for normal advice
targetInterceptor, // invoke target without considering advice, if optimized
new SerializableNoOp(), // no override for methods mapped to this
targetDispatcher,
this.advisedDispatcher,
new EqualsInterceptor(this.advised),
new HashCodeInterceptor(this.advised)
};
......
Callback[] callbacks;
if(isStatic && isFrozen) {
......
} eles {
callbacks = mainCallbacks;
}
return callbacks;
}
4. 后文介绍
IOC容器原理、Spring EL表达式和Spring AOP原理。