public interface Person {
String searchHouse();
}
複製代碼
public class MasterProxy implements Person {
private Person person;
public MasterProxy(Person person) {
this.person = person;
}
@Override
public String searchHouse() {
System.out.println("我是鏈家,我幫別人找房子..");
//第一個參數是target,也就是被代理類的對象;第二個參數是方法中的參數
String msg = person.searchHouse();
System.out.println("------------------------");
System.out.println("| | |");
System.out.println("| | |");
System.out.println("| | |");
System.out.println("|------- ------- -----");
System.out.println(" |");
System.out.println("|----------------------|");
System.out.println("我是鏈家,已經找到了..");
return msg;
}
}
複製代碼
public class ProxyTest {
@Test
public void testJDKObject() {
Person person = new Master();
MasterProxy masterProxy = new MasterProxy(person);
String sb = masterProxy.searchHouse();
System.out.println(sb);
}
}
複製代碼
缺點:java
public class Master implements Person{
@Override
public String searchHouse() {
System.out.println("我須要找一個整租兩室一廳的房子");
return "done";
}
public static String pay() {
System.out.println("我支付了");
return "我支付了";
}
public final String sign() {
System.out.println("我簽約了");
return "我簽約了";
}
}
複製代碼
JDK緩存
/** * 代理對象,不須要實現接口 * * 代理對象不須要實現接口,可是目標對象必定要實現接口,不然不能用動態代理 * @param <T> */
public class HomeLineJDK<T> implements InvocationHandler {
private Person target;
public T createProxyInstance(Person target){
this.target = target;
Class clazz = target.getClass();
//指定當前目標對象使用類加載器,獲取加載器的方法是固定的
//目標對象實現的接口的類型,使用泛型方式確認類型
//事件處理,執行目標對象的方法時,會觸發事件處理器的方法,會把當前執行目標對象的方法做爲參數傳入
T obj = (T)Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this);
// new ProxyClass().getClazz("jdkObject");
return obj;
}
public T createProxyInstance(Class clazz){
T obj = (T)Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this);
new ProxyClass().getClazz("jdkClass");
return obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//System.out.println("我是鏈家,我幫別人找房子..");
//第一個參數是target,也就是被代理類的對象;第二個參數是方法中的參數
Object msg = method.invoke(target, args);
System.out.println("我是鏈家,已經找到了..");
return msg;
}
}
複製代碼
cglibide
/** * Cglib代理,也叫做子類代理,它是在內存中構建一個子類對象從而實現對目標對象功能的擴展. */
public class HomeLineCglib implements MethodInterceptor {
private Object target;
public <T> T createProxyInstance(T targetObject){
this.target = targetObject; //給業務對象賦值
Enhancer enhancer = new Enhancer(); //建立增強器,用來建立動態代理類 也就是cglib中的一個class generator
enhancer.setSuperclass(this.target.getClass()); //爲增強器指定要代理的業務類(即:爲下面生成的代理類指定父類)
//設置回調:對於代理類上全部方法的調用,都會調用CallBack,而Callback則須要實現intercept()方法進行攔
enhancer.setCallback(this);
// 建立動態代理類對象並返回
T o = (T)enhancer.create();
// new ProxyClass().getCglibClazz(enhancer);
return o;
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("我是鏈家,我幫別人找房子..");
//第一個參數是target,也就是被代理類的對象;第二個參數是方法中的參數
Object msg = methodProxy.invoke(this.target, objects);
System.out.println("我是鏈家,已經找完了..");
return msg;
}
}
複製代碼
測試:性能
public class InvacationTest {
@Test
public void testJDKObject() {
Person person = new HomeLineJDK<Person>().createProxyInstance(new Master());
String sb = person.searchHouse();
// System.out.println(sb);
}
@Test
public void testJDKCLass() {
Person person1 = new HomeLineJDK<Person>().createProxyInstance(Master.class);
String sb1 = person1.searchHouse();
System.out.println(sb1);
}
@Test
public void testCglib() {
Master master = new Master();
master = new HomeLineCglib().createProxyInstance(master);
master.searchHouse();
}
@Test
public void testStaticCglib() {
Master master = new Master();
master = new HomeLineCglib().createProxyInstance(master);
master.pay();
}
@Test
public void testFinalCglib() {
Master master = new Master();
master = new HomeLineCglib().createProxyInstance(master);
master.sign();
}
}
複製代碼
咱們能夠$Proxy0獲取到代理對象的class,反編譯出生成的代理類測試
public class ProxyClass {
//獲取到jdk代理對象的class
public void getClazz(String fileName){
String path = "D://"+fileName+".class";
byte[] classFile = ProxyGenerator.generateProxyClass("$Proxy0",Master.class.getInterfaces());
FileOutputStream out = null;
try {
out = new FileOutputStream(path);
out.write(classFile);
out.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//獲取到cglib對應的class
public void getCglibClazz(Enhancer enhancer){
String path = "D://cglib.class";
byte[] classFile = new byte[0];
try {
classFile = enhancer.getStrategy().generate(enhancer);
} catch (Exception e) {
e.printStackTrace();
}
FileOutputStream out = null;
try {
out = new FileOutputStream(path);
out.write(classFile);
out.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
複製代碼
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
import services.proxy.Person;
public final class $Proxy0 extends Proxy implements Person {
private static Method m1;
private static Method m2;
private static Method m3;
private static Method m0;
public $Proxy0(InvocationHandler var1) throws {
super(var1);
}
public final boolean equals(Object var1) throws {
try {
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final String toString() throws {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final String searchHouse() throws {
try {
return (String)super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final int hashCode() throws {
try {
return (Integer)super.h.invoke(this, m0, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m2 = Class.forName("java.lang.Object").getMethod("toString");
m3 = Class.forName("services.proxy.Person").getMethod("searchHouse");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
複製代碼
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
import services.proxy.Person;
public final class $Proxy0 extends Proxy implements Person {
private static Method m1;
private static Method m2;
private static Method m3;
private static Method m0;
public $Proxy0(InvocationHandler var1) throws {
super(var1);
}
public final boolean equals(Object var1) throws {
try {
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final String toString() throws {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final String searchHouse() throws {
try {
return (String)super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final int hashCode() throws {
try {
return (Integer)super.h.invoke(this, m0, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m2 = Class.forName("java.lang.Object").getMethod("toString");
m3 = Class.forName("services.proxy.Person").getMethod("searchHouse");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
複製代碼
package services.proxy;
import org.junit.Test;
public class ProxyPerofrmanceTest {
@Test
public void testTime(){
testCglibCreateTime(10000);
testJdkCreateTime(10000);
System.out.println("-------------------");
testCglibExecuteTime(10);
testCglibExecuteTime(100);
testCglibExecuteTime(1000);
testCglibExecuteTime(10000);
testCglibExecuteTime(100000);
testCglibExecuteTime(1000000);
testCglibExecuteTime(10000000);
System.out.println("-------------------");
System.out.println("-------------------");
testJdkExecuteTime(10);
testJdkExecuteTime(100);
testJdkExecuteTime(1000);
testJdkExecuteTime(10000);
testJdkExecuteTime(100000);
testJdkExecuteTime(1000000);
testJdkExecuteTime(10000000);
}
public void testJdkExecuteTime(int times){
Person person = new HomeLineJDK<Person>().createProxyInstance(new Master());
long jdks = System.currentTimeMillis();
for (int i = 0;i<times;i++){
person.searchHouse();
}
long jdke = System.currentTimeMillis();
System.out.println("jdk"+times+"次執行方法到處理時間:"+(jdke-jdks));
}
public void testJdkCreateTime(int times){
long jdks = System.currentTimeMillis();
for (int i = 0;i<times;i++){
Person person = new HomeLineJDK<Person>().createProxyInstance(new Master());
}
long jdke = System.currentTimeMillis();
System.out.println("jkd建立代理對象"+times+"次處理時間:"+(jdke-jdks));
}
}
複製代碼
jdk和cglib第一次建立對象會將對象緩存,因此咱們先建立一次去掉建立對象時間this
jdk | cglib |
---|---|
2 ms | 228 ms |
接下來咱們看執行對應方法的耗時spa
次數 | jdk | cglib |
---|---|---|
10 | 0 | 17 |
100 | 1 | 0 |
1000 | 0 | 1 |
10000 | 2 | 4 |
100000 | 5 | 4 |
1000000 | 13 | 9 |
10000000 | 94 | 44 |
能夠看到在建立對象並緩存到內存中的時候,cglib耗時比較jdk嚴重。可是在正直的執行過程當中咱們能夠看到開始的時候jdk的性能優於cglib當達到必定調用量的時候cglib的性能較jdk要好。代理