预计分两篇写,第一篇是基础和一般用法,第二篇详细写下动态代理。本篇基础主要来自《Think in java》阅读笔记。
代理是基本的设计模式之一。
是为了提供额外的或不同的操作,而插入的用来代替“实际”对象的对象。
将额外的操作从“实际”对象中分离到不同的地方,特别是希望能够容易的做出修改,从没有使用额外操作转为使用这些操作,或者反过来时,代理就显得很有用。
设计模式的关键就是封装修改-因此需要修改事务以证明这种模式的正确性。如,当希望跟踪Dog中的方法调用,或度量这些调用的开销,这些代码肯定不希望将其合并到应用中的代码,此时代理可以很容易的添加或移除他们。
通俗说,代理就是对象需要一些附加或不同的操作时,使用第三方对象操作原对象以及处理这些操作,从而达到不直接修改原对象的目的的一种设计模式。
静态代理是在编译时就将接口、实现类、代理类全部写出来,但若是需要很多代理,就需要每一次都这样写一遍,这就可能导致时间与资源的浪费。 此时可以使用动态代理来代替静态代理。
接口类 Animal
public interface Animal {
void doBark();
void somethingElse(String arg);
}
具体实现类 Dog
public class Dog implements Animal {
public void doBark() {
PrintUtill.println("doBark wow");
}
public void somethingElse(String arg) {
PrintUtill.println("somethingElse " + arg);
}
}
代理类 SimpleProxy
public class SimpleProxy implements Animal {
private Animal proxied;
public SimpleProxy(Animal proxied) {
this.proxied = proxied;
}
public void doBark() {
PrintUtill.println("SimpleProxy doSomething");
proxied.doBark();
}
public void somethingElse(String arg) {
PrintUtill.println("SimpleProxy somethingElse " + arg);
proxied.somethingElse(arg);
}
}
测试代理类 SimpleProxyDemo
/**
* consumer 接收的Animal,所以它无法知道正则获得的到底是Dog还是SimpleProxy,因为这两者都实现了Animal。
*
* 但是SimpleProxy已经被插入到consumer与Dog之间,因此它会执行操作,然后调用Dog上相同的方法。
*/
public class SimpleProxyDemo {
public static void consumer(Animal iface){
iface.doBark();
iface.somethingElse("WindCoder.com");
}
public static void main(String[] args) {
consumer(new Dog());
consumer(new SimpleProxy(new Dog()));
}
}
测试结果:
doBark wow
somethingElse WindCoder.com
SimpleProxy doSomething
doBark wow
SimpleProxy somethingElse WindCoder.com
somethingElse WindCoder.com
动态代理可以动态地创建代理并动态地处理对所代理方法的调用。
在动态代理上所做的所有调用都会被重定向到单一的调用处理器上。
该调用处理器的工作是揭示调用的类型并确定相应的对策。
InvocationHandler接口的实现类DynamicProxyHandler
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class DynamicProxyHandler implements InvocationHandler {
private Object proxied;
public DynamicProxyHandler(Object proxied) {
this.proxied = proxied;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("*** proxy: " + proxy.getClass() + " , method: " + method + " , args: " + args);
if (args != null){
for (Object arg: args){
PrintUtill.println(" " + arg);
}
}
return method.invoke(proxied, args);
}
}
动态代理测试类SimpleDynamicProxy
public class SimpleDynamicProxy {
public static void consumer(Animal iface){
iface.doBark();
iface.somethingElse("windCoder.com DynamicProxy");
}
public static void main(String[] args) {
Dog dog = new Dog();
consumer(dog);
// Insert a proxy and call again
Animal prox = (Animal) Proxy.newProxyInstance(
Animal.class.getClassLoader(),
new Class[]{Animal.class},
new DynamicProxyHandler(dog)
);
consumer(prox);
}
}
doBark wow
somethingElse windCoder.com DynamicProxy
*** proxy: class com.sun.proxy.$Proxy0 , method: public abstract void Others.base.SimpleProxy.Animal.doBark() , args: null
doBark wow
*** proxy: class com.sun.proxy.$Proxy0 , method: public abstract void Others.base.SimpleProxy.Animal.somethingElse(java.lang.String) , args: [Ljava.lang.Object;@4b67cf4d
windCoder.com DynamicProxy
somethingElse windCoder.com DynamicProxy
动态代理测试类SimpleDynamicProxy.java中
Animal prox = (Animal) Proxy.newProxyInstance(
Animal.class.getClassLoader(),
new Class[]{Animal.class},
new DynamicProxyHandler(dog)
);
通过调用静态方法Proxy.newProxyInstance()可以创建动态代理,这个方法需要得到:
动态代理可以将所有调用重定向到调用处理器。
通常会向调用处理器的构造器传递一个“实际”对象的引用,从而使得调用处理器在执行其中介任务时,可以将请求转发。
InvocationHandler接口的实现类DynamicProxyHandler.java中:
method.invoke(proxied, args);
亦既:
public Object invoke(Object obj, Object... args)
invoke()方法中传递进来了代理对象,以防使用时需要区分请求的来源,但在许多情况下并不关心这一点。
在invoke()内部,在代理调用方法时,对接口的调用将被重定向为对代理的调用,因此要格外当心。
通常,执行被代理的操作,然后使用Method.invoke()将请求转发给被代对象,并传入必需的参数。
初看起来可能有些受限,就像只能执行泛化操作一样。
但可以通过传递其他的参数,来过滤某些方法的调用。
JDK动态代理: 只能代理实现了接口的类,没有实现接口的类不能实现JDK动态代理。
Cglib代理: 针对类来实现代理,对指定目标产生一个子类 通过方法拦截技术拦截所有父类方法的调用。
在实现内部,CGLIB库使用了ASM这一个轻量但高性能的字节码操作框架来转化字节码,产生新类。
1.首先定义业务类,无需实现接口(当然,实现接口也可以,不影响的)
public class DogCGlib {
public void doBark() {
PrintUtill.println("doBark wow CGlib");
}
public void somethingElse(String arg) {
PrintUtill.println("somethingElse CGlib" + arg);
}
}
2.实现 MethodInterceptor方法代理接口,创建代理类
public class CGlibProxy implements MethodInterceptor {
public Object getInstance(Class target){
//创建加强器,用来创建动态代理类
Enhancer enhancer = new Enhancer();
//为加强器指定要代理的业务类(即:为下面生成的代理类指定父类)
enhancer.setSuperclass(target);
//设置回调:对于代理类上所有方法的调用,都会调用CallBack,而Callback则需要实现intercept()方法进行拦
enhancer.setCallback(this);
// 创建动态代理类对象并返回
return enhancer.create();
}
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("windcoder.com日志开始...");
//代理类调用父类的方法
proxy.invokeSuper(obj, args);
System.out.println("windcoder.com日志结束...");
return null;
}
}
3.创建业务类和代理类对象,然后通过 代理类对象.getInstance(业务类对象) 返回一个动态代理类对象(它是业务类的子类,可以用业务类引用指向它)。最后通过动态代理类对象进行方法调用。
public class CGLIBDemo {
public static void main(String[] args) {
// 设置输出目录,方便之后查看CGLIB生成的class---非必选项
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "./tmp/");
// 正式执行
CGlibProxy proxy = new CGlibProxy();
DogCGlib dog = (DogCGlib)proxy.getInstance(DogCGlib.class);
dog.doBark();
PrintUtill.printlnRule();
dog.somethingElse(" 你好");
}
}
《Java编程思想 第4版》
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有