package com.lidl.com.lidl.web;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* @author lidongling
* 动态:在程序运行时运用反射机制动态创建而成。
* 一个代理只能代理一种类型,而且是在编译器就已经确定被代理的对象。而动态代理是在运行时,通过反射机制实现动态代理,并且能够代理各种类型的对象
* 在Java中要想实现动态代理机制,需要java.lang.reflect.InvocationHandler接口和 java.lang.reflect.Proxy 类的支持
*动态代理优点:
* 动态代理与静态代理相比较,最大的好处是接口中声明的所有方法都被转移到调用处理器一个集中的方法中处理(InvocationHandler.invoke)。
* 这样,在接口方法数量比较多的时候,我们可以进行灵活处理,而不需要像静态代理那样每一个方法进行中转。而且动态代理的应用使我们的类职责更加单一,复用性更强
*
* 总结:
* 其实所谓代理,就是一个人或者一个机构代表另一个人或者另一个机构采取行动。在一些情况下,一个客户不想或者不能够直接引用一个对象,而代理对象可以在客户端和目标对象之前起到中介的作用。
* 代理对象就是把被代理对象包装一层,在其内部做一些额外的工作,比如用户需要上facebook,而普通网络无法直接访问,网络代理帮助用户先翻墙,然后再访问facebook。这就是代理的作用了。
* 纵观静态代理与动态代理,它们都能实现相同的功能,而我们看从静态代理到动态代理的这个过程,我们会发现其实动态代理只是对类做了进一步抽象和封装,使其复用性和易用性得到进一步
* 提升而这不仅仅符合了面向对象的设计理念,其中还有AOP的身影,这也提供给我们对类抽象的一种参考。关于动态代理与AOP的关系,个人觉得AOP是一种思想,而动态代理是一种AOP思想的实现!
*/
public class DynamicProxy {
public static void main(String[] args) {
MyInvocationHandler hander = new MyInvocationHandler();
//11种实现方式
/*hander.setPp(new man());
//1 CLassLoader loader:类的加载器
//2 Class<?> interfaces:得到全部的接口
//3 InvocationHandler h:得到InvocationHandler接口的子类的实例
Person pman = (Person) Proxy.newProxyInstance(Dxc7.class.getClassLoader(),new Class[]{Person.class},hander);
pman.work();
hander.setPp(new woman());
Person pwman = (Person)Proxy.newProxyInstance(Dxc7.class.getClassLoader(),new Class[]{Person.class},hander);
pwman.work();*/
//22种实现方式
Person pman1=(Person) hander.newProxyInstance(new man());
pman1.work();
Person pwman1=(Person) hander.newProxyInstance(new woman());
pwman1.work();
}
}
interface Person{
void work();
}
//真实角色1
class man implements Person{
@Override
public void work() {
System.out.println("------like a man---------");
}
}
//真实角色2
class woman implements Person{
@Override
public void work() {
System.out.println("------like a woman---------");
}
}
//代理角色
//动态代理类只能代理接口(不支持抽象类),代理类都需要实现InvocationHandler类,
// 实现invoke方法。该invoke方法就是调用被代理接口的所有方法时需要调用的,该invoke方法返回的值是被代理接口的一个实现类
/*被代理对象pp通过参数传递进来,我们通过pp.getClass().getClassLoader()获取ClassLoader对象,
然后通过pp.getClass().getInterfaces()获取它实现的所有接口,
然后将pp包装到实现了InvocationHandler接口的LogHandler对象中。通过newProxyInstance函数我们就获得了一个动态代理对象。
可以看到,我们可以通过MyInvocationHandler代理不同类型的对象,如果我们把对外的接口都通过动态代理来实现,那么所有的函数调用最终都会经过invoke函数的转发,
因此我们就可以在这里做一些自己想做的操作,比如日志系统、事务、拦截器、权限控制等。这也就是AOP(面向切面编程)的基本原理。*/
class MyInvocationHandler implements InvocationHandler {
private Person pp;
//11种实现方式
/*public void setPp(Person pp) {
this.pp = pp;
}*/
//22种实现方式
//绑定关系,也就是关联到哪个接口(与具体的实现类绑定)的哪些方法将被调用时,执行invoke方法。
public Object newProxyInstance(Person pp){
this.pp=pp;
//该方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例
//第一个参数指定产生代理对象的类加载器,需要将其指定为和目标对象同一个类加载器
//第二个参数要实现和目标对象一样的接口,所以只需要拿到目标对象的实现接口
//第三个参数表明这些被拦截的方法在被拦截时需要执行哪个InvocationHandler的invoke方法
//根据传入的目标返回一个代理对象
return Proxy.newProxyInstance(pp.getClass().getClassLoader(),
pp.getClass().getInterfaces(),this);
}
//Object proxy:被代理的对象
//Method method:要调用的方法
//Object[] args:方法调用时所需要参数
//关联的这个实现类的方法被调用时将被执行
//InvocationHandler接口的方法,proxy表示代理,method表示原对象被调用的方法,args表示方法的参数
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object rs=null;
System.out.println("---------invoke--before------------");
//调用目标方法
rs = method.invoke(pp,args);
System.out.println("---------invoke--after------------");
return rs;
}
}