动态代理的技术入口就是java.lang.reflect.Proxy类
按照我目前的了解,动态代理是一种AOP编程技术,比如过滤器Filter就是这样的,spring的AOP思想的具体技术就是动态代理,最最主要的就是玩类反射 。
代理其实有静态和动态之分,显然动态的更好啦。比如框架中的框架Sprin里面最为核心的拦截器就是将动变代理成了可配置的方式方便使用。
使用动态代理,需要一个接口,和这个接口的实现类,而我们的代理类的位置就是这个接口的实现类的兄弟类。
一个入门级别的例子,相当简洁了。
也就是一个基础接口,然后一个类去实现这个接口,这个类也就是我们要进行代理的,所谓代理就是在这个类的这个方法的执行前后拦截一下,先执行我这边的方法,再看看要不要放行
/**
* 基础接口
* @author BarryLee
* @2018年11月10日@下午1:14:47
*/
public interface IPerson {
public abstract void talk();
}
/**
* 被代理的实现类
* @author BarryLee
* @2018年11月10日@下午1:15:09
*/
public class Person implements IPerson{
@Override
public void talk() {
System.out.println(" 小梨花又在讲个不停 .. ");
}
}
/**
* 代理测试类
* @author BarryLee
* @2018年11月10日@下午1:15:28
*/
public class ProxyDemo {
/*
* 传入想要代理的对象,然后就可以获取代理后的对象
*/
public Object getProxy(Person p) {
// p是原型对象 - 也就是我原来要执行的对象 - 在method.invoke中调用了这个p对象
// 开始代理,返回一个代理后的对象object
return Proxy.newProxyInstance(
ProxyDemo.class.getClassLoader(),
p.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(" 代理前 .. ");
Object returnVal = method.invoke(p, args);
System.out.println(" 代理后 .. ");
return returnVal;
}
});
}
/*
* 调用,传入一个原型对象new Person()
* 将代理后的对象强转为IPerson
* 这里的person是代理后的对象,调用这个对象中的talk
*/
@Test
public void proxyDemo() {
IPerson person = (IPerson)getProxy( new Person() );
person.talk();
}
}
---------這是一條分割綫--------
看个简单的例子
几个类:Cat实现IAnimal接口;Person实现IPerson接口;ProxyUtil是动态代理的实现,而Ex是使用这个代理类。
1.Ex
package cn.bl.proxy.v2;
import org.junit.Test;
/**
* 在这里执行
* @author BarryLee
* @2018年9月20日@下午2:30:53
*/
public class Ex {
@Test
public void test() {
Person p = new Person("小梨花");
IPerson person = (IPerson)ProxyUtil.getProxy(p);
person.sayHi();
Cat c = new Cat("小妖");
IAnimal cat = (IAnimal)ProxyUtil.getProxy(c);
cat.run();
}
/* 执行前。。。
小梨花在打招呼
执行后。。。
执行前。。。
小妖猫在吃狗粮
执行后。。。
*/
}
2.ProxyUtil
package cn.bl.proxy.v2;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* 动态代理
* 动态代理类(以下简称为代理类)是一个实现在创建类时在运行时指定的接口列表的类,该类具有下面描述的行为。
* 代理接口 是代理类实现的一个接口。 代理实例 是代理类的一个实例。
* 每个代理实例都有一个关联的调用处理程序 对象,它可以实现接口 InvocationHandler。
* 通过其中一个代理接口的代理实例上的方法调用将被指派到实例的调用处理程序的 Invoke 方法,
* 并传递代理实例、识别调用方法的 java.lang.reflect.Method 对象以及包含参数的 Object 类型的数组。
* 调用处理程序以适当的方式处理编码的方法调用,并且它返回的结果将作为代理实例上方法调用的结果返回。
* @author BarryLee
* @2018年9月20日@下午2:32:16
*/
public class ProxyUtil implements InvocationHandler{
Object srcObj = null;//目标对象
public ProxyUtil(Object srcObj) {//构造传参
this.srcObj = srcObj;
}
public static Object getProxy (Object object) {
return Proxy.newProxyInstance(
//ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
object.getClass().getClassLoader(), //可以用:XXX.class.getClassLoader()
object.getClass().getInterfaces(),
new ProxyUtil(object));
}
//覆盖InvocationHandler的一个抽象类
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("执行前。。。");
Object returnObj = method.invoke(srcObj, args);
System.out.println("执行后。。。\r\n");
return returnObj;
/*
上面几个参数:
1.proxy - 在其上调用方法的代理实例
2.method - 对应于在代理实例上调用的接口方法的 Method 实例。
Method 对象的声明类将是在其中声明方法的接口,该接口可以是代理类赖以继承方法的代理接口的超接口。
3.args - 包含传入代理实例上方法调用的参数值的对象数组,如果接口方法不使用参数,则为 null。
基本类型的参数被包装在适当基本包装器类(如 java.lang.Integer 或 java.lang.Boolean)的实例中。
*/
}
}
3.两个接口
package cn.bl.proxy.v2;
public interface IPerson {
public abstract void sayHi();
}
package cn.bl.proxy.v2;
public interface IAnimal {
public abstract void run();
}
4.这两个接口的实现类
package cn.bl.proxy.v2;
public class Person implements IPerson{
private String name ;
public Person(String name) {
this.name = name;
}
@Override
public void sayHi() {
System.out.println(this.name+"在打招呼");
}
}
package cn.bl.proxy.v2;
public class Cat implements IAnimal{
private String name;
public Cat(String name) {
this.name = name;
}
@Override
public void run() {
System.out.println(this.name+"猫在吃狗粮");
}
}