本文轉自:https://blog.csdn.net/yinwenjie/article/details/78048671
=============================================
(接上文《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;
}
<==== 上一篇 =====>
Spring/Boot/Cloud系列知識(3)— — 代理模式(中)
<==== 下一篇 =====>
Spring/Boot/Cloud系列知識(5)— — Spring EL(1)