Java的三種代理模式(Spring動(dòng)態(tài)代理對(duì)象)
點(diǎn)擊上方藍(lán)色字體,選擇“標(biāo)星公眾號(hào)”
優(yōu)質(zhì)文章,第一時(shí)間送達(dá)
1.代理模式
代理(Proxy)是一種設(shè)計(jì)模式,提供了對(duì)目標(biāo)對(duì)象另外的訪問方式;即通過代理對(duì)象訪問目標(biāo)對(duì)象.這樣做的好處是:可以在目標(biāo)對(duì)象實(shí)現(xiàn)的基礎(chǔ)上,增強(qiáng)額外的功能操作,即擴(kuò)展目標(biāo)對(duì)象的功能.
這里使用到編程中的一個(gè)思想:不要隨意去修改別人已經(jīng)寫好的代碼或者方法,如果需改修改,可以通過代理的方式來擴(kuò)展該方法
舉個(gè)例子來說明代理的作用:假設(shè)我們想邀請(qǐng)一位明星,那么并不是直接連接明星,而是聯(lián)系明星的經(jīng)紀(jì)人,來達(dá)到同樣的目的.明星就是一個(gè)目標(biāo)對(duì)象,他只要負(fù)責(zé)活動(dòng)中的節(jié)目,而其他瑣碎的事情就交給他的代理人(經(jīng)紀(jì)人)來解決.這就是代理思想在現(xiàn)實(shí)中的一個(gè)例子
用圖表示如下:

代理模式的關(guān)鍵點(diǎn)是:代理對(duì)象與目標(biāo)對(duì)象.代理對(duì)象是對(duì)目標(biāo)對(duì)象的擴(kuò)展,并會(huì)調(diào)用目標(biāo)對(duì)象
1.1.靜態(tài)代理(類似于裝飾者模式)
靜態(tài)代理在使用時(shí),需要定義接口或者父類,被代理對(duì)象與代理對(duì)象一起實(shí)現(xiàn)相同的接口或者是繼承相同父類.
下面舉個(gè)案例來解釋:
模擬保存動(dòng)作,定義一個(gè)保存動(dòng)作的接口:IUserDao.java,然后目標(biāo)對(duì)象實(shí)現(xiàn)這個(gè)接口的方法UserDao.java,此時(shí)如果使用靜態(tài)代理方 式,就需要在代理對(duì)象(UserDaoProxy.java)中也實(shí)現(xiàn)IUserDao接口.調(diào)用的時(shí)候通過調(diào)用代理對(duì)象的方法來調(diào)用目標(biāo)對(duì)象.
需要注意的是,代理對(duì)象與目標(biāo)對(duì)象要實(shí)現(xiàn)相同的接口,然后通過調(diào)用相同的方法來調(diào)用目標(biāo)對(duì)象的方法
代碼示例:
接口:IUserDao.java
/**
* 接口
*/
public interface IUserDao {
void save();
}
目標(biāo)對(duì)象:UserDao.java
/**
* 接口實(shí)現(xiàn)
* 目標(biāo)對(duì)象
*/
public class UserDao implements IUserDao {
public void save() {
System.out.println("----已經(jīng)保存數(shù)據(jù)!----");
}
}
代理對(duì)象:UserDaoProxy.java
/**
* 代理對(duì)象,靜態(tài)代理
*/
public class UserDaoProxy implements IUserDao{
//接收保存目標(biāo)對(duì)象
private IUserDao target;
public UserDaoProxy(IUserDao target){
this.target=target;
}
public void save() {
System.out.println("開始事務(wù)...");
target.save();//執(zhí)行目標(biāo)對(duì)象的方法
System.out.println("提交事務(wù)...");
}
}
測試類:App.java
/**
* 測試類
*/
public class App {
public static void main(String[] args) {
//目標(biāo)對(duì)象
UserDao target = new UserDao();
//代理對(duì)象,把目標(biāo)對(duì)象傳給代理對(duì)象,建立代理關(guān)系
UserDaoProxy proxy = new UserDaoProxy(target);
proxy.save();//執(zhí)行的是代理的方法
}
}
靜態(tài)代理總結(jié):
1.可以做到在不修改目標(biāo)對(duì)象的功能前提下,對(duì)目標(biāo)功能擴(kuò)展.
2.缺點(diǎn):
因?yàn)榇韺?duì)象需要與目標(biāo)對(duì)象實(shí)現(xiàn)一樣的接口,所以會(huì)有很多代理類,類太多.同時(shí),一旦接口增加方法,目標(biāo)對(duì)象與代理對(duì)象都要維護(hù).
如何解決靜態(tài)代理中的缺點(diǎn)呢?答案是可以使用動(dòng)態(tài)代理方式
1.2.動(dòng)態(tài)代理
動(dòng)態(tài)代理有以下特點(diǎn):
1.代理對(duì)象,不需要實(shí)現(xiàn)接口
2.代理對(duì)象的生成,是利用JDK的API,動(dòng)態(tài)的在內(nèi)存中構(gòu)建代理對(duì)象(需要我們指定創(chuàng)建代理對(duì)象/目標(biāo)對(duì)象實(shí)現(xiàn)的接口的類型)
3.動(dòng)態(tài)代理也叫做:JDK代理,接口代理
JDK中生成代理對(duì)象的API
代理類所在包:java.lang.reflect.Proxy
JDK實(shí)現(xiàn)代理只需要使用newProxyInstance方法,但是該方法需要接收三個(gè)參數(shù),完整的寫法是:
static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h )
注意該方法是在Proxy類中是靜態(tài)方法,且接收的三個(gè)參數(shù)依次為:
ClassLoader loader,:指定當(dāng)前目標(biāo)對(duì)象使用類加載器,獲取加載器的方法是固定的Class<?>[] interfaces,:目標(biāo)對(duì)象實(shí)現(xiàn)的接口的類型,使用泛型方式確認(rèn)類型InvocationHandler h:事件處理,執(zhí)行目標(biāo)對(duì)象的方法時(shí),會(huì)觸發(fā)事件處理器的方法,會(huì)把當(dāng)前執(zhí)行目標(biāo)對(duì)象的方法作為參數(shù)傳入
代碼示例:
接口類IUserDao.java以及接口實(shí)現(xiàn)類,目標(biāo)對(duì)象UserDao是一樣的,沒有做修改.在這個(gè)基礎(chǔ)上,增加一個(gè)代理工廠類 (ProxyFactory.java),將代理類寫在這個(gè)地方,然后在測試類(需要使用到代理的代碼)中先建立目標(biāo)對(duì)象和代理對(duì)象的聯(lián)系,然后代用代理 對(duì)象的中同名方法
接口和默認(rèn)實(shí)現(xiàn):
package aop;
public interface IUserDao {
void save();
void delete();
void saveAndDelete();
}
實(shí)現(xiàn)類:
package aop;
public class UserDao implements IUserDao {
public void save() {
System.out.println("save");
}
public void delete() {
System.out.println("delete");
}
public void saveAndDelete() {
save();
delete();
}
}
代理工廠類:ProxyFactory.java
package aop;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* 創(chuàng)建動(dòng)態(tài)代理對(duì)象
* 動(dòng)態(tài)代理不需要實(shí)現(xiàn)接口,但是需要指定接口類型
*/
public class ProxyFactory {
//維護(hù)一個(gè)目標(biāo)對(duì)象
private Object target;
public ProxyFactory(Object target) {
this.target = target;
}
//給目標(biāo)對(duì)象生成代理對(duì)象
public Object getProxyInstance() {
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("開始事務(wù)2");
//運(yùn)用反射執(zhí)行目標(biāo)對(duì)象方法
Object returnValue = method.invoke(target, args);
System.out.println("提交事務(wù)2");
return returnValue;
}
}
);
}
}
測試類:
package aop;
/**
* @author: 喬利強(qiáng)
* @date: 2020/12/11 19:55
* @description:
*/
public class Client {
public static void main(String[] args) {
// 目標(biāo)對(duì)象
UserDao target = new UserDao();
// class aop.UserDao
System.out.println(target.getClass());
// 給目標(biāo)對(duì)象,創(chuàng)建代理對(duì)象
IUserDao proxy = (IUserDao) new ProxyFactory(target).getProxyInstance();
// class $Proxy0 內(nèi)存中動(dòng)態(tài)生成的代理對(duì)象
System.out.println(proxy.getClass());
proxy.save();
System.out.println("===1===");
proxy.delete();
System.out.println("===2===");
proxy.saveAndDelete();
}
}
結(jié)果:
class aop.UserDao
class com.sun.proxy.$Proxy0
開始事務(wù)2
save
提交事務(wù)2
===1===
開始事務(wù)2
delete
提交事務(wù)2
===2===
開始事務(wù)2
save
delete
提交事務(wù)2
可以看出saveAndDelete 內(nèi)部調(diào)用save和delete方法沒有走攔截到的方法,這個(gè)很好理解,內(nèi)部調(diào)用直接走的方法調(diào)用,沒用代理對(duì)象。
如果我們想查看生產(chǎn)的代理類:
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true" );
總結(jié):
代理對(duì)象不需要實(shí)現(xiàn)接口,但是目標(biāo)對(duì)象一定要實(shí)現(xiàn)接口,否則不能用動(dòng)態(tài)代理
1.3.Cglib代理(基于繼承的方式實(shí)現(xiàn))

pom如下:
<!-- https://mvnrepository.com/artifact/cglib/cglib -->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.2.12</version>
</dependency>
上面的靜態(tài)代理和動(dòng)態(tài)代理模式都是要求目標(biāo)對(duì)象是實(shí)現(xiàn)一個(gè)接口的目標(biāo)對(duì)象,但是有時(shí)候目標(biāo)對(duì)象只是一個(gè)單獨(dú)的對(duì)象,并沒有實(shí)現(xiàn)任何的接口,這個(gè)時(shí)候就可以使用以目標(biāo)對(duì)象子類的方式類實(shí)現(xiàn)代理,這種方法就叫做:Cglib代理
Cglib代理,也叫作子類代理,它是在內(nèi)存中構(gòu)建一個(gè)子類對(duì)象從而實(shí)現(xiàn)對(duì)目標(biāo)對(duì)象功能的擴(kuò)展.
JDK的動(dòng)態(tài)代理有一個(gè)限制,就是使用動(dòng)態(tài)代理的對(duì)象必須實(shí)現(xiàn)一個(gè)或多個(gè)接口,如果想代理沒有實(shí)現(xiàn)接口的類,就可以使用Cglib實(shí)現(xiàn).
Cglib是一個(gè)強(qiáng)大的高性能的代碼生成包,它可以在運(yùn)行期擴(kuò)展java類與實(shí)現(xiàn)java接口.它廣泛的被許多AOP的框架使用,例如Spring AOP和synaop,為他們提供方法的interception(攔截)
Cglib包的底層是通過使用一個(gè)小而塊的字節(jié)碼處理框架ASM來轉(zhuǎn)換字節(jié)碼并生成新的類.不鼓勵(lì)直接使用ASM,因?yàn)樗竽惚仨殞?duì)JVM內(nèi)部結(jié)構(gòu)包括class文件的格式和指令集都很熟悉.
Cglib子類代理實(shí)現(xiàn)方法:
1.需要引入cglib的jar文件,但是Spring的核心包中已經(jīng)包括了Cglib功能,所以直接引入pring-core-3.2.5.jar即可.
2.引入功能包后,就可以在內(nèi)存中動(dòng)態(tài)構(gòu)建子類
3.代理的類不能為final,否則報(bào)錯(cuò)
4.目標(biāo)對(duì)象的方法如果為final/static,那么就不會(huì)被攔截,即不會(huì)執(zhí)行目標(biāo)對(duì)象額外的業(yè)務(wù)方法.
5.如果方法為static,private則無法進(jìn)行代理。
代碼:
dao和接口同上面JDK代理。
Cglib代理工廠
package aop;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* @author: 喬利強(qiáng)
* @date: 2020/12/11 20:05
* @description:
*/
public class CglibProxyFactory implements MethodInterceptor {
public CglibProxyFactory() {
}
/**
* 1、代理對(duì)象;2、委托類方法;3、方法參數(shù);4、代理方法的MethodProxy對(duì)象。
*
* @param o
* @param method
* @param objects
* @param methodProxy
* @return
* @throws Throwable
*/
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("事務(wù)開始......" + method.getName());
Object o1 = methodProxy.invokeSuper(o, objects);
System.out.println("事務(wù)結(jié)束......." + method.getName());
return o1;
}
}
測試類:
package aop;
import net.sf.cglib.core.DebuggingClassWriter;
import net.sf.cglib.proxy.Enhancer;
/**
* @author: 喬利強(qiáng)
* @date: 2020/12/11 20:07
* @description:
*/
public class CglibClient {
public static void main(String[] args) {
//在指定目錄下生成動(dòng)態(tài)代理類,我們可以反編譯看一下里面到底是一些什么東西
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "G:/proxy");
CglibProxyFactory cglibProxy = new CglibProxyFactory();
//jdk需要提供接口,cglib需要是非私有類,且不能處理final關(guān)鍵字修飾的方法
Enhancer enhancer = new Enhancer();
//設(shè)置父類
enhancer.setSuperclass(UserDao.class);
//設(shè)置回調(diào)對(duì)象
enhancer.setCallback(cglibProxy);
UserDao proxy = (UserDao) enhancer.create();
proxy.save();
System.out.println("===1===");
proxy.delete();
System.out.println("===2===");
proxy.saveAndDelete();
}
}
結(jié)果: 可以看出通過方法內(nèi)部調(diào)用也走了代理。這個(gè)很好理解相當(dāng)于是調(diào)用的是繼承類的方法。
事務(wù)開始......save
save
事務(wù)結(jié)束.......save
===1===
事務(wù)開始......delete
delete
事務(wù)結(jié)束.......delete
===2===
事務(wù)開始......saveAndDelete
事務(wù)開始......save
save
事務(wù)結(jié)束.......save
事務(wù)開始......delete
delete
事務(wù)結(jié)束.......delete
事務(wù)結(jié)束.......saveAndDelete
關(guān)于cglib動(dòng)態(tài)代理中invokeSuper和invoke的區(qū)別參考:https://blog.csdn.net/z69183787/article/details/106878203/
補(bǔ)充:在Spring的AOP中自調(diào)用AOP無效。簡單研究了下,是調(diào)用invoke的效果,如下:
1.修改代理方法
package aop;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* @Author: qlq
* @Description
* @Date: 20:23 2021/1/24
*/
public class CglibProxyFactory implements MethodInterceptor {
private Object target;
public CglibProxyFactory(Object target) {
super();
this.target = target;
}
/**
* 1、代理對(duì)象;2、委托類方法;3、方法參數(shù);4、代理方法的MethodProxy對(duì)象。
*
* @param o
* @param method
* @param objects
* @param methodProxy
* @return
* @throws Throwable
*/
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("事務(wù)開始......" + method.getName());
Object o1 = methodProxy.invoke(target, objects);
System.out.println("事務(wù)結(jié)束......." + method.getName());
return o1;
}
}
2.測試類如下:
package aop;
import net.sf.cglib.core.DebuggingClassWriter;
import net.sf.cglib.proxy.Enhancer;
/**
* @Author: qlq
* @Description
* @Date: 20:26 2021/1/24
*/
public class CglibClient {
public static void main(String[] args) {
//在指定目錄下生成動(dòng)態(tài)代理類,我們可以反編譯看一下里面到底是一些什么東西
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "G:/proxy");
UserDao userDao = new UserDao();
CglibProxyFactory cglibProxy = new CglibProxyFactory(userDao);
//jdk需要提供接口,cglib需要是非私有類,且不能處理final關(guān)鍵字修飾的方法
Enhancer enhancer = new Enhancer();
//設(shè)置父類
enhancer.setSuperclass(UserDao.class);
//設(shè)置回調(diào)對(duì)象
enhancer.setCallback(cglibProxy);
UserDao proxy = (UserDao) enhancer.create();
proxy.save();
System.out.println("===1===");
proxy.delete();
System.out.println("===2===");
proxy.saveAndDelete();
}
}
結(jié)果:可以看到方法內(nèi)部調(diào)用沒有走代理
事務(wù)開始......save
save
事務(wù)結(jié)束.......save
===1===
事務(wù)開始......delete
delete
事務(wù)結(jié)束.......delete
===2===
事務(wù)開始......saveAndDelete
save
delete
事務(wù)結(jié)束.......saveAndDelete
簡單理解,invoke方法調(diào)用的對(duì)象沒有增強(qiáng)過(target 模板對(duì)象),invokeSuper方法調(diào)用的對(duì)象已經(jīng)是增強(qiáng)了的(proxy 代理對(duì)象),所以會(huì)再走一遍 MethodInterceptor的 interceptor方法,如果是個(gè)攔截器鏈條,就會(huì)重新在走一次攔截器鏈。
而且在invoke和invokeSuper中,this指代的對(duì)象不同,
(1) methodProxy.invokeSuper(o, objects); 中this是代理對(duì)象:aop.UserDao$$EnhancerByCGLIB$$86ae564d@6a1aab78
(2) methodProxy.invoke(target, objects); 中this指向target對(duì)象:aop.UserDao@eafc191
補(bǔ)充:Spring的AOP調(diào)用也是用的invoke的套路,我們在AOP中打印this可以看出是目標(biāo)target對(duì)象還是代理proxy對(duì)象。結(jié)果看出是目標(biāo)target對(duì)象
com.xm.ggn.test.aop.TestServiceImpl@330fff8e也可以簡單查看Spring代理:org.springframework.aop.framework.CglibAopProxy.DynamicAdvisedInterceptor#intercept
@Override
@Nullable
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
Object target = null;
TargetSource targetSource = this.advised.getTargetSource();
try {
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// Get as late as possible to minimize the time we "own" the target, in case it comes from a pool...
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
Object retVal;
// Check whether we only have one InvokerInterceptor: that is,
// no real advice, but just reflective invocation of the target.
if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
// We can skip creating a MethodInvocation: just invoke the target directly.
// Note that the final invoker must be an InvokerInterceptor, so we know
// it does nothing but a reflective operation on the target, and no hot
// swapping or fancy proxying.
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = methodProxy.invoke(target, argsToUse);
}
else {
// We need to create a method invocation...
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
}
retVal = processReturnType(proxy, target, method, retVal);
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}
1.4 在Spring的AOP編程中代理的選擇方式:
AOP調(diào)用時(shí)序圖;

查看DefaultAopProxyFactory的源碼:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package org.springframework.aop.framework;
import java.io.Serializable;
import java.lang.reflect.Proxy;
import org.springframework.aop.SpringProxy;
public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {
public DefaultAopProxyFactory() {
}
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if (!config.isOptimize() && !config.isProxyTargetClass() && !this.hasNoUserSuppliedProxyInterfaces(config)) {
return new JdkDynamicAopProxy(config);
} else {
Class<?> targetClass = config.getTargetClass();
if (targetClass == null) {
throw new AopConfigException("TargetSource cannot determine target class: Either an interface or a target is required for proxy creation.");
} else {
return (AopProxy)(!targetClass.isInterface() && !Proxy.isProxyClass(targetClass) ? new ObjenesisCglibAopProxy(config) : new JdkDynamicAopProxy(config));
}
}
}
private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {
Class<?>[] ifcs = config.getProxiedInterfaces();
return ifcs.length == 0 || ifcs.length == 1 && SpringProxy.class.isAssignableFrom(ifcs[0]);
}
}
Spring中強(qiáng)制使用Cglib代理
<aop:aspectj-autoproxy proxy-target-class="true" />
SpringBoot中強(qiáng)制使用Cglib代理

總結(jié):
如果加入容器的目標(biāo)對(duì)象有實(shí)現(xiàn)接口,用JDK代理
如果目標(biāo)對(duì)象沒有實(shí)現(xiàn)接口,用Cglib代理
如果目標(biāo)對(duì)象實(shí)現(xiàn)了接口,且強(qiáng)制使用cglib代理,則會(huì)使用cglib代理
參考:http://www.cnblogs.com/qlqwjy/p/8533261.html
補(bǔ)充:查看JDK動(dòng)態(tài)代理和cglib 代理的原理
Interface1 接口,采用JDK動(dòng)態(tài)代理
package com.xm.ggn.test.proxy;
public interface Interface1 {
void method1();
void method2(String test);
}
CgClass1 類,采用cglib 代理
package com.xm.ggn.test.proxy;
public class CgClass1 {
void method1() {
System.out.println("com.xm.ggn.test.proxy.CgClass1.method1");
}
void method2(String test) {
System.out.println("com.xm.ggn.test.proxy.CgClass1.method2");
}
}
Client
package com.xm.ggn.test.proxy;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class Client {
public static void main(String[] args) throws Exception {
// jdk 動(dòng)態(tài)代理
Interface1 o = (Interface1) Proxy.newProxyInstance(Interface1.class.getClassLoader(), new Class[]{Interface1.class}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("java.lang.reflect.InvocationHandler.invoke " + method + " " + args);
return "123";
}
});
o.method1();
o.method2("Interface1 method2");
//****************cglib
//jdk需要提供接口,cglib需要是非私有類,且不能處理final關(guān)鍵字修飾的方法
Enhancer enhancer = new Enhancer();
//設(shè)置父類
enhancer.setSuperclass(CgClass1.class);
//設(shè)置回調(diào)對(duì)象
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("方法前......" + method.getName());
Object o1 = methodProxy.invokeSuper(o, objects);
System.out.println("方法后......." + method.getName());
return o1;
}
});
CgClass1 cgClass1 = (CgClass1) enhancer.create();
cgClass1.method1();
cgClass1.method2("cg method2");
Thread.sleep(50 * 10000);
}
}
啟動(dòng)之后控制臺(tái)如下:
java.lang.reflect.InvocationHandler.invoke public abstract void com.xm.ggn.test.proxy.Interface1.method1() null
java.lang.reflect.InvocationHandler.invoke public abstract void com.xm.ggn.test.proxy.Interface1.method2(java.lang.String) [Ljava.lang.Object;@5025a98f
方法前......method1
com.xm.ggn.test.proxy.CgClass1.method1
方法后.......method1
方法前......method2
com.xm.ggn.test.proxy.CgClass1.method2
方法后.......method2
然后采用arthas 進(jìn)行查看
(1) 查看JDK動(dòng)態(tài)代理
sc 查看類信息
[arthas@69520]$ sc *.Interface1
com.sun.proxy.$Proxy0
com.xm.ggn.test.proxy.Interface1
反編譯查看代理類信息
[arthas@69520]$ jad com.sun.proxy.$Proxy0
ClassLoader:
+-sun.misc.Launcher$AppClassLoader@18b4aac2
+-sun.misc.Launcher$ExtClassLoader@35db61e9
Location:
/*
* Decompiled with CFR.
*
* Could not load the following classes:
* com.xm.ggn.test.proxy.Interface1
*/
package com.sun.proxy;
import com.xm.ggn.test.proxy.Interface1;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
public final class $Proxy0
extends Proxy
implements Interface1 {
private static Method m1;
private static Method m2;
private static Method m4;
private static Method m3;
private static Method m0;
public $Proxy0(InvocationHandler invocationHandler) {
super(invocationHandler);
}
public final boolean equals(Object object) {
try {
return (Boolean)this.h.invoke(this, m1, new Object[]{object});
}
catch (Error | RuntimeException throwable) {
throw throwable;
}
catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
public final String toString() {
try {
return (String)this.h.invoke(this, m2, null);
}
catch (Error | RuntimeException throwable) {
throw throwable;
}
catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
public final void method2(String string) {
try {
this.h.invoke(this, m4, new Object[]{string});
return;
}
catch (Error | RuntimeException throwable) {
throw throwable;
}
catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
public final void method1() {
try {
this.h.invoke(this, m3, null);
return;
}
catch (Error | RuntimeException throwable) {
throw throwable;
}
catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
public final int hashCode() {
try {
return (Integer)this.h.invoke(this, m0, null);
}
catch (Error | RuntimeException throwable) {
throw throwable;
}
catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
m4 = Class.forName("com.xm.ggn.test.proxy.Interface1").getMethod("method2", Class.forName("java.lang.String"));
m3 = Class.forName("com.xm.ggn.test.proxy.Interface1").getMethod("method1", new Class[0]);
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
return;
}
catch (NoSuchMethodException noSuchMethodException) {
throw new NoSuchMethodError(noSuchMethodException.getMessage());
}
catch (ClassNotFoundException classNotFoundException) {
throw new NoClassDefFoundError(classNotFoundException.getMessage());
}
}
}
可以看到是繼承Proxy 對(duì)象,實(shí)現(xiàn)Interface1 接口。
1》構(gòu)造方法會(huì)調(diào)用父類的構(gòu)造,IDEA 查看父類構(gòu)造
java.lang.reflect.Proxy#Proxy(java.lang.reflect.InvocationHandler)
protected InvocationHandler h;
protected Proxy(InvocationHandler h) {
Objects.requireNonNull(h);
this.h = h;
}
2》 查看method1、method2 方法,實(shí)際是反射調(diào)用InvocationHandler, 也就是我們上面匿名類創(chuàng)建的對(duì)象(所以這個(gè)匿名類一般會(huì)根據(jù)方法名稱判斷是toString、hashcode方法進(jìn)行特殊處理)
public final void method2(String string) {
try {
this.h.invoke(this, m4, new Object[]{string});
return;
}
catch (Error | RuntimeException throwable) {
throw throwable;
}
catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
public final void method1() {
try {
this.h.invoke(this, m3, null);
return;
}
catch (Error | RuntimeException throwable) {
throw throwable;
}
catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
(2) 查看Cglib 代理
1》搜索類
[arthas@104968]$ sc *.CgClass1
com.xm.ggn.test.proxy.CgClass1
com.xm.ggn.test.proxy.CgClass1$$EnhancerByCGLIB$$f752d1b3
2》反編譯查看類:可以看到主要是繼承代理類,實(shí)現(xiàn)cglib 的類,核心是通過MethodInteceptor 進(jìn)行處理的
[arthas@104968]$ jad com.xm.ggn.test.proxy.CgClass1$$EnhancerByCGLIB$$f752d1b3
ClassLoader:
+-sun.misc.Launcher$AppClassLoader@18b4aac2
+-sun.misc.Launcher$ExtClassLoader@1f256477
Location:
/E:/xiangmu/bs-media-gitee/bs-media/media-server/target/classes/
/*
* Decompiled with CFR.
*
* Could not load the following classes:
* com.xm.ggn.test.proxy.CgClass1
*/
package com.xm.ggn.test.proxy;
import com.xm.ggn.test.proxy.CgClass1;
import java.lang.reflect.Method;
import net.sf.cglib.core.ReflectUtils;
import net.sf.cglib.core.Signature;
import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.Factory;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class CgClass1$$EnhancerByCGLIB$$f752d1b3
extends CgClass1
implements Factory {
private boolean CGLIB$BOUND;
public static Object CGLIB$FACTORY_DATA;
private static final ThreadLocal CGLIB$THREAD_CALLBACKS;
private static final Callback[] CGLIB$STATIC_CALLBACKS;
private MethodInterceptor CGLIB$CALLBACK_0;
private static Object CGLIB$CALLBACK_FILTER;
private static final Method CGLIB$method1$0$Method;
private static final MethodProxy CGLIB$method1$0$Proxy;
private static final Object[] CGLIB$emptyArgs;
private static final Method CGLIB$method2$1$Method;
private static final MethodProxy CGLIB$method2$1$Proxy;
private static final Method CGLIB$equals$2$Method;
private static final MethodProxy CGLIB$equals$2$Proxy;
private static final Method CGLIB$toString$3$Method;
private static final MethodProxy CGLIB$toString$3$Proxy;
private static final Method CGLIB$hashCode$4$Method;
private static final MethodProxy CGLIB$hashCode$4$Proxy;
private static final Method CGLIB$clone$5$Method;
private static final MethodProxy CGLIB$clone$5$Proxy;
static void CGLIB$STATICHOOK1() {
CGLIB$THREAD_CALLBACKS = new ThreadLocal();
CGLIB$emptyArgs = new Object[0];
Class<?> clazz = Class.forName("com.xm.ggn.test.proxy.CgClass1$$EnhancerByCGLIB$$f752d1b3");
Class<?> clazz2 = Class.forName("java.lang.Object");
Method[] methodArray = ReflectUtils.findMethods(new String[]{"equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;"}, clazz2.getDeclaredMethods());
CGLIB$equals$2$Method = methodArray[0];
CGLIB$equals$2$Proxy = MethodProxy.create(clazz2, clazz, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$2");
CGLIB$toString$3$Method = methodArray[1];
CGLIB$toString$3$Proxy = MethodProxy.create(clazz2, clazz, "()Ljava/lang/String;", "toString", "CGLIB$toString$3");
CGLIB$hashCode$4$Method = methodArray[2];
CGLIB$hashCode$4$Proxy = MethodProxy.create(clazz2, clazz, "()I", "hashCode", "CGLIB$hashCode$4");
CGLIB$clone$5$Method = methodArray[3];
CGLIB$clone$5$Proxy = MethodProxy.create(clazz2, clazz, "()Ljava/lang/Object;", "clone", "CGLIB$clone$5");
clazz2 = Class.forName("com.xm.ggn.test.proxy.CgClass1");
Method[] methodArray2 = ReflectUtils.findMethods(new String[]{"method1", "()V", "method2", "(Ljava/lang/String;)V"}, clazz2.getDeclaredMethods());
CGLIB$method1$0$Method = methodArray2[0];
CGLIB$method1$0$Proxy = MethodProxy.create(clazz2, clazz, "()V", "method1", "CGLIB$method1$0");
CGLIB$method2$1$Method = methodArray2[1];
CGLIB$method2$1$Proxy = MethodProxy.create(clazz2, clazz, "(Ljava/lang/String;)V", "method2", "CGLIB$method2$1");
}
final void CGLIB$method1$0() {
super.method1();
}
final void method1() {
MethodInterceptor methodInterceptor = this.CGLIB$CALLBACK_0;
if (methodInterceptor == null) {
CgClass1$$EnhancerByCGLIB$$f752d1b3.CGLIB$BIND_CALLBACKS(this);
methodInterceptor = this.CGLIB$CALLBACK_0;
}
if (methodInterceptor != null) {
Object object = methodInterceptor.intercept(this, CGLIB$method1$0$Method, CGLIB$emptyArgs, CGLIB$method1$0$Proxy);
return;
}
super.method1();
}
final void CGLIB$method2$1(String string) {
super.method2(string);
}
final void method2(String string) {
MethodInterceptor methodInterceptor = this.CGLIB$CALLBACK_0;
if (methodInterceptor == null) {
CgClass1$$EnhancerByCGLIB$$f752d1b3.CGLIB$BIND_CALLBACKS(this);
methodInterceptor = this.CGLIB$CALLBACK_0;
}
if (methodInterceptor != null) {
Object object = methodInterceptor.intercept(this, CGLIB$method2$1$Method, new Object[]{string}, CGLIB$method2$1$Proxy);
return;
}
super.method2(string);
}
final boolean CGLIB$equals$2(Object object) {
return super.equals(object);
}
public final boolean equals(Object object) {
MethodInterceptor methodInterceptor = this.CGLIB$CALLBACK_0;
if (methodInterceptor == null) {
CgClass1$$EnhancerByCGLIB$$f752d1b3.CGLIB$BIND_CALLBACKS(this);
methodInterceptor = this.CGLIB$CALLBACK_0;
}
if (methodInterceptor != null) {
Object object2 = methodInterceptor.intercept(this, CGLIB$equals$2$Method, new Object[]{object}, CGLIB$equals$2$Proxy);
return object2 == null ? false : (Boolean)object2;
}
return super.equals(object);
}
final String CGLIB$toString$3() {
return super.toString();
}
public final String toString() {
MethodInterceptor methodInterceptor = this.CGLIB$CALLBACK_0;
if (methodInterceptor == null) {
CgClass1$$EnhancerByCGLIB$$f752d1b3.CGLIB$BIND_CALLBACKS(this);
methodInterceptor = this.CGLIB$CALLBACK_0;
}
if (methodInterceptor != null) {
return (String)methodInterceptor.intercept(this, CGLIB$toString$3$Method, CGLIB$emptyArgs, CGLIB$toString$3$Proxy);
}
return super.toString();
}
final int CGLIB$hashCode$4() {
return super.hashCode();
}
public final int hashCode() {
MethodInterceptor methodInterceptor = this.CGLIB$CALLBACK_0;
if (methodInterceptor == null) {
CgClass1$$EnhancerByCGLIB$$f752d1b3.CGLIB$BIND_CALLBACKS(this);
methodInterceptor = this.CGLIB$CALLBACK_0;
}
if (methodInterceptor != null) {
Object object = methodInterceptor.intercept(this, CGLIB$hashCode$4$Method, CGLIB$emptyArgs, CGLIB$hashCode$4$Proxy);
return object == null ? 0 : ((Number)object).intValue();
}
return super.hashCode();
}
final Object CGLIB$clone$5() throws CloneNotSupportedException {
return super.clone();
}
protected final Object clone() throws CloneNotSupportedException {
MethodInterceptor methodInterceptor = this.CGLIB$CALLBACK_0;
if (methodInterceptor == null) {
CgClass1$$EnhancerByCGLIB$$f752d1b3.CGLIB$BIND_CALLBACKS(this);
methodInterceptor = this.CGLIB$CALLBACK_0;
}
if (methodInterceptor != null) {
return methodInterceptor.intercept(this, CGLIB$clone$5$Method, CGLIB$emptyArgs, CGLIB$clone$5$Proxy);
}
return super.clone();
}
public static MethodProxy CGLIB$findMethodProxy(Signature signature) {
String string = ((Object)signature).toString();
switch (string.hashCode()) {
case -724084219: {
if (!string.equals("method1()V")) break;
return CGLIB$method1$0$Proxy;
}
case -518805714: {
if (!string.equals("method2(Ljava/lang/String;)V")) break;
return CGLIB$method2$1$Proxy;
}
case -508378822: {
if (!string.equals("clone()Ljava/lang/Object;")) break;
return CGLIB$clone$5$Proxy;
}
case 1826985398: {
if (!string.equals("equals(Ljava/lang/Object;)Z")) break;
return CGLIB$equals$2$Proxy;
}
case 1913648695: {
if (!string.equals("toString()Ljava/lang/String;")) break;
return CGLIB$toString$3$Proxy;
}
case 1984935277: {
if (!string.equals("hashCode()I")) break;
return CGLIB$hashCode$4$Proxy;
}
}
return null;
}
public CgClass1$$EnhancerByCGLIB$$f752d1b3() {
CgClass1$$EnhancerByCGLIB$$f752d1b3 cgClass1$$EnhancerByCGLIB$$f752d1b3 = this;
CgClass1$$EnhancerByCGLIB$$f752d1b3.CGLIB$BIND_CALLBACKS(cgClass1$$EnhancerByCGLIB$$f752d1b3);
}
public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] callbackArray) {
CGLIB$THREAD_CALLBACKS.set(callbackArray);
}
public static void CGLIB$SET_STATIC_CALLBACKS(Callback[] callbackArray) {
CGLIB$STATIC_CALLBACKS = callbackArray;
}
private static final void CGLIB$BIND_CALLBACKS(Object object) {
block2: {
Object object2;
block3: {
CgClass1$$EnhancerByCGLIB$$f752d1b3 cgClass1$$EnhancerByCGLIB$$f752d1b3 = (CgClass1$$EnhancerByCGLIB$$f752d1b3)object;
if (cgClass1$$EnhancerByCGLIB$$f752d1b3.CGLIB$BOUND) break block2;
cgClass1$$EnhancerByCGLIB$$f752d1b3.CGLIB$BOUND = true;
object2 = CGLIB$THREAD_CALLBACKS.get();
if (object2 != null) break block3;
object2 = CGLIB$STATIC_CALLBACKS;
if (CGLIB$STATIC_CALLBACKS == null) break block2;
}
cgClass1$$EnhancerByCGLIB$$f752d1b3.CGLIB$CALLBACK_0 = (MethodInterceptor)((Callback[])object2)[0];
}
}
public Object newInstance(Callback[] callbackArray) {
CgClass1$$EnhancerByCGLIB$$f752d1b3.CGLIB$SET_THREAD_CALLBACKS(callbackArray);
CgClass1$$EnhancerByCGLIB$$f752d1b3 cgClass1$$EnhancerByCGLIB$$f752d1b3 = new CgClass1$$EnhancerByCGLIB$$f752d1b3();
CgClass1$$EnhancerByCGLIB$$f752d1b3.CGLIB$SET_THREAD_CALLBACKS(null);
return cgClass1$$EnhancerByCGLIB$$f752d1b3;
}
public Object newInstance(Callback callback) {
CgClass1$$EnhancerByCGLIB$$f752d1b3.CGLIB$SET_THREAD_CALLBACKS(new Callback[]{callback});
CgClass1$$EnhancerByCGLIB$$f752d1b3 cgClass1$$EnhancerByCGLIB$$f752d1b3 = new CgClass1$$EnhancerByCGLIB$$f752d1b3();
CgClass1$$EnhancerByCGLIB$$f752d1b3.CGLIB$SET_THREAD_CALLBACKS(null);
return cgClass1$$EnhancerByCGLIB$$f752d1b3;
}
public Object newInstance(Class[] classArray, Object[] objectArray, Callback[] callbackArray) {
CgClass1$$EnhancerByCGLIB$$f752d1b3 cgClass1$$EnhancerByCGLIB$$f752d1b3;
CgClass1$$EnhancerByCGLIB$$f752d1b3.CGLIB$SET_THREAD_CALLBACKS(callbackArray);
Class[] classArray2 = classArray;
switch (classArray.length) {
case 0: {
cgClass1$$EnhancerByCGLIB$$f752d1b3 = new CgClass1$$EnhancerByCGLIB$$f752d1b3();
break;
}
default: {
throw new IllegalArgumentException("Constructor not found");
}
}
CgClass1$$EnhancerByCGLIB$$f752d1b3.CGLIB$SET_THREAD_CALLBACKS(null);
return cgClass1$$EnhancerByCGLIB$$f752d1b3;
}
public Callback getCallback(int n) {
MethodInterceptor methodInterceptor;
CgClass1$$EnhancerByCGLIB$$f752d1b3.CGLIB$BIND_CALLBACKS(this);
switch (n) {
case 0: {
methodInterceptor = this.CGLIB$CALLBACK_0;
break;
}
default: {
methodInterceptor = null;
}
}
return methodInterceptor;
}
public void setCallback(int n, Callback callback) {
switch (n) {
case 0: {
this.CGLIB$CALLBACK_0 = (MethodInterceptor)callback;
break;
}
}
}
public Callback[] getCallbacks() {
CgClass1$$EnhancerByCGLIB$$f752d1b3.CGLIB$BIND_CALLBACKS(this);
CgClass1$$EnhancerByCGLIB$$f752d1b3 cgClass1$$EnhancerByCGLIB$$f752d1b3 = this;
return new Callback[]{this.CGLIB$CALLBACK_0};
}
public void setCallbacks(Callback[] callbackArray) {
Callback[] callbackArray2 = callbackArray;
CgClass1$$EnhancerByCGLIB$$f752d1b3 cgClass1$$EnhancerByCGLIB$$f752d1b3 = this;
this.CGLIB$CALLBACK_0 = (MethodInterceptor)callbackArray[0];
}
static {
CgClass1$$EnhancerByCGLIB$$f752d1b3.CGLIB$STATICHOOK1();
}
}
作者 | QiaoZhi
來源 | cnblogs.com/qlqwjy/p/7550609.html

