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原理。
|