標簽:love 系統 代理類 oca 解決 效率 問題 instance byte
7、代理模式
代理模式是指爲其他對象提供一種代理,以控制對這個對象的訪問,屬于結構型模式。在某些情況下,一個對象不適合或者不能直接引用另一個對象,而代理對象可以在客戶端和目標對象之間起到中介的作用。
代理模式一般包含三種角色:
抽象主題角色(Subject):抽象主題類的主要職責是聲明真實主題與代理的共同接口方法,該類可以是接口也可以是抽象方法。
真实主题角色(RealSubject):该类也被称为被代理類,该类定义了代理所表示的真实对象,是负责执行系統真正的业务逻辑对象。
代理主题角色Proxy:也被称为代理類,其内部有RealSubjuct的引用,因此具备完全的对RealSubject的代理权。客户端调用代理对象的方法,但是会在代理对象前后增加一些处理代码。
代理模式的通用寫法:
package com.jdwa.nomalproxy;
public interface ISubject {
void request();
}
package com.jdwa.nomalproxy;
public class RealSubject implements ISubject{
@Override
public void request() {
System.out.println("real service is called ");
}
}
package com.jdwa.nomalproxy;
public class Proxy implements ISubject {
private ISubject subject;
public Proxy(ISubject subject){
this.subject = subject;
}
@Override
public void request() {
before();
subject.request();
after();
}
private void before(){
System.out.println("called before real service ...");
}
private void after(){
System.out.println("called after real service ...");
}
}
package com.jdwa.nomalproxy;
public class Client {
public static void main(String[] args) {
ISubject subject = new RealSubject();
Proxy proxy = new Proxy(subject);
proxy.request();
}
}
從靜態代理帶動態代理:
package com.jdwa.staticproxy;
public interface IPerson {
void findLove();
}
package com.jdwa.staticproxy;
public class Tom implements IPerson {
@Override
public void findLove() {
System.out.println("must be a beautiful girl");
}
}
package com.jdwa.staticproxy;
public class TomFather implements IPerson {
private IPerson tom;
public TomFather(IPerson tom){
this.tom = tom;
}
@Override
public void findLove() {
before();
tom.findLove();
after();
}
private void before(){
System.out.println("find a suitable girl ...");
}
private void after(){
System.out.println("Get ready to be together ...");
}
}
package com.jdwa.staticproxy;
public class Client {
public static void main(String[] args) {
IPerson tom = new Tom();
IPerson tomFather = new TomFather(tom);
tomFather.findLove();
}
}
動態代理
package com.jdwa.staticproxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class MatchMarker implements InvocationHandler {
private IPerson target;
public IPerson getInstance(IPerson target){
this.target = target;
Class<?> clazz = target.getClass();
return (IPerson) Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
before();
Object result = method.invoke(this.target,args);
after();
return result;
}
private void before(){
System.out.println("I‘m matchmarker,I hava already collect your infomation ,start to look for");
}
private void after(){
System.out.println("They are very satisfied with each other");
}
}
測試
package com.jdwa.staticproxy;
public class Client {
public static void main(String[] args) {
// IPerson tom = new Tom();
// IPerson tomFather = new TomFather(tom);
// tomFather.findLove();
MatchMarker matchMarker = new MatchMarker();
IPerson tom = matchMarker.getInstance(new Tom());
tom.findLove();
}
}
这就是JDK自带的動態代理实现。
我们都知道jdk動態代理采用字节重组,重新生成对象来代替原始对象,以达到動態代理的目的。jdk動態代理生成对象的步骤如下:
a、獲取被代理對象的引用,並獲取他的所有接口,反射獲取。
b、jdk動態代理類重新生成一个新的类,同时新的类要实现被代理類实现的所有接口
c、動態生成Java代碼新加的業務邏輯方法由一定的邏輯代碼調用
d、編譯新生成的Java代碼,得到class
e、重新加載到JVM中運行
我們通過將內存中的對象字節碼輸出,然後反編譯,可以查看代理對象的源代碼。
package com.jdwa.staticproxy;
import sun.misc.ProxyGenerator;
import java.io.FileOutputStream;
public class Client {
public static void main(String[] args) throws Exception{
// IPerson tom = new Tom();
// IPerson tomFather = new TomFather(tom);
// tomFather.findLove();
// MatchMarker matchMarker = new MatchMarker();
// IPerson tom = matchMarker.getInstance(new Tom());
// tom.findLove();
IPerson person = new MatchMarker().getInstance(new Tom());
person.findLove();
byte[] bytes = ProxyGenerator.generateProxyClass("$Proxy0",new Class[]{IPerson.class});
FileOutputStream fos = new FileOutputStream("E://$Proxy0.class");
fos.write(bytes);
fos.close();
}
}
通过源代码我们可以发现$Proxy0类继承了Proxy类,同时还实现了IPerson接口,重写了findLove方法。在静态块中用反射查找了目标 对象的所有方法,而且保存了所有方法的引用,重写的方法用反射调用目标对象的方法。这些代码,都是jdk帮我们自动生成的。
CGLIB實現
package com.jdwa.staticproxy;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class CGLibMatchMarker implements MethodInterceptor {
public Object getInstance(Class<?> clazz) throws Exception{
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
before();
Object obj = methodProxy.invokeSuper(o,objects);
after();
return obj;
}
private void before(){
System.out.println("cglib ----I‘m matchmarker,I hava already collect your infomation ,start to look for");
}
private void after(){
System.out.println("cglib ----They are very satisfied with each other");
}
}
package com.jdwa.staticproxy;
import sun.misc.ProxyGenerator;
import java.io.FileOutputStream;
public class Client {
public static void main(String[] args) throws Exception{
// IPerson tom = new Tom();
// IPerson tomFather = new TomFather(tom);
// tomFather.findLove();
// MatchMarker matchMarker = new MatchMarker();
// IPerson tom = matchMarker.getInstance(new Tom());
// tom.findLove();
// IPerson person = new MatchMarker().getInstance(new Tom());
// person.findLove();
// byte[] bytes = ProxyGenerator.generateProxyClass("$Proxy0",new Class[]{IPerson.class});
// FileOutputStream fos = new FileOutputStream("E://$Proxy0.class");
// fos.write(bytes);
// fos.close();
Tom tom = (Tom) new CGLibMatchMarker().getInstance(Tom.class);
tom.findLove();
}
}
cglib的执行效率要高于jdk的,就是因为CGLib采用了FastClass机制,他的原理简单来说就是:为代理類和被代理類各生成一个类,这个类会为代理類和被代理類的方法分配一个INDEX(int类型);这个INDEX当作一个入参,FastClass就可以直接定位要调用的方法并直接进行调用,省去了反射调用,所以调用效率比JDK代理通过反射调用高。
標簽:love 系統 代理類 oca 解決 效率 問題 instance byte
原文地址:https://www.cnblogs.com/caozz/p/proxy.html