建议看这个文章前先看我的静态代理那篇文章
【动态代理】:情景二,一个客户买TF口红,另外几个客户·MAC或者防晒霜又想买,要买的东西增加了,这时候权限代理和日志代理多写几个,代理里面体现是,买东西时间接口方法要增加,客户增加,代理增加,因为客户和代理都要实现买东西的时间接口,因此,接口一变动,两者都要变动是不是很麻烦 ?而且日志和权限校验是所有用户都要走的,能不能只用一个日志代理,根据传入的客户对象不同而去调用不同的购买方法呢。然而我们看之上传进去的都是代码写死的对象,如果是前端传过来的对象呢。所以这就需要动态代理。
静态代理和动态代理区别是,动态代理是运行的时候在内存自动生成代理类,不需要我们手写。
凡是运行中自动创建的必定涉及到java反射
动态代理的API:
在java.lang.reflect包中有一个代理类。
- java.lang.reflect.Proxy
-
static Object
newProxyInstance(ClassLoader loader,类<?>[] interfaces,InvocationHandler h)
返回指定的接口,将方法调用指定的调用处理程序的代理类的一个实例。
编写接口:
package StaticProxy;
public interface BuyInterface {
public void buyTF();
public void buyBook();
}
目标对象类
package StaticProxy;
public class TFClient implements BuyInterface {
@Override
public void buyTF() {
System.out.println("I want a TF lipstick");
}
@Override
public void buyBook() {
}
}
权限handler:
package JDKProxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class AuthHandler implements InvocationHandler {
private Object target;
public AuthHandler(Object object){
super();
this.target=object;
}
/*
* proxy:被代理的对象
*method:被代理的对象的方法
* args:方法中的参数
* */
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("开始验证权限");
method.invoke(target);
System.out.println("结束验证权限");
return null;
}
}
运行类:
package JDKProxy;
import StaticProxy.BuyInterface;
import StaticProxy.TFClient;
import java.awt.*;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
public class TestProxy {
InvocationHandler invocationHandler;
public static void main(String[] args) {
TFClient me=new TFClient();
TestProxy testProxy=new TestProxy();
testProxy.generateAuthProxy(me);
}
public <T>void generateAuthProxy(T t){
invocationHandler=new AuthHandler(t);
Class<?> cls=t.getClass();
BuyInterface buyInterface= (BuyInterface) Proxy.newProxyInstance(cls.getClassLoader(),cls.getInterfaces(),invocationHandler);
buyInterface.buyTF();
}
}
运行结果:
根据传入的目标对象建立代理类
现在我们建立一个日志代理类:
先建立Handler
package JDKProxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class LogHandler implements InvocationHandler {
private Object target;
public LogHandler(Object object){
super();
this.target=object;
}
/*
* proxy:被代理的对象
*method:被代理的对象的方法
* args:方法中的参数
* */
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("开始打印日志");
method.invoke(target);
System.out.println("结束打印日志");
return null;
}
}
运行调用,传入对象:me
package JDKProxy;
import StaticProxy.BuyInterface;
import StaticProxy.TFClient;
import java.awt.*;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
public class TestProxy {
InvocationHandler invocationHandler;
public static void main(String[] args) {
TFClient me=new TFClient();
TestProxy testProxy=new TestProxy();
testProxy.generateAuthProxy(me);
testProxy.generateLogProxy(me);
}
public <T>void generateAuthProxy(T t){
invocationHandler=new AuthHandler(t);
Class<?> cls=t.getClass();
BuyInterface buyInterface= (BuyInterface) Proxy.newProxyInstance(cls.getClassLoader(),cls.getInterfaces(),invocationHandler);
buyInterface.buyTF();
}
public <T>void generateLogProxy(T t){
invocationHandler=new LogHandler(t);
Class<?> cls=t.getClass();
BuyInterface buyInterface= (BuyInterface) Proxy.newProxyInstance(cls.getClassLoader(),cls.getInterfaces(),invocationHandler);
buyInterface.buyTF();
}
}
运行结果如上:
现在我建立一个买书的买家这回不买TF了,不过使用同样的日志类和权限类:
package JDKProxy;
import StaticProxy.BookClient;
import StaticProxy.BuyInterface;
import StaticProxy.TFClient;
import java.awt.*;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
public class TestProxy {
InvocationHandler invocationHandler;
public static void main(String[] args) {
TestProxy testProxy=new TestProxy();
// TFClient me=new TFClient();
// testProxy.generateAuthProxy(me);
// testProxy.generateLogProxy(me);
BookClient bookClient=new BookClient();
testProxy.generateAuthProxy(bookClient);
testProxy.generateLogProxy(bookClient);
}
public <T>void generateAuthProxy(T t){
invocationHandler=new AuthHandler(t);
Class<?> cls=t.getClass();
BuyInterface buyInterface= (BuyInterface) Proxy.newProxyInstance(cls.getClassLoader(),cls.getInterfaces(),invocationHandler);
buyInterface.buyTF();
buyInterface.buyBook();
}
public <T>void generateLogProxy(T t){
invocationHandler=new LogHandler(t);
Class<?> cls=t.getClass();
BuyInterface buyInterface= (BuyInterface) Proxy.newProxyInstance(cls.getClassLoader(),cls.getInterfaces(),invocationHandler);
buyInterface.buyTF();
buyInterface.buyBook();
}
}
同样可以使用日志打印和权限的Handler这样无论几个目标对象就都可以使用相当于工具类的权限认证和日志打印了,当然这样的设计模式还有不方便之处,比如每次都要打印出所有的实现方法等。而且只能代理实现了接口的类。没有实现接口的类不能获得代理,这就比较蛋疼了哈。那么为了解决这个同点,又出现了CGLib这个我们下节课学哈