目录
一、什么是动态代理?
动态代理是指代理类对象在程序运行时由JVM根据反射机制动态生成的。动态代理不需要定义代理类的.java源文件——>jdk运行期间动态创建class字节码并加载JVM——>代理对象在程序运行的过程中动态在内存构建,可以灵活的进行业务功能的切换。
二、JDK动态代理
A.目标对象必须实现业务接口。
B.JDK代理对象不需要实现业务接口。
C.JDK动态代理的对象在程序运行前不存在,在程序运行时动态的在内存中构建。
D.JDK动态代理灵活的进行业务功能的切换。
E.本类中的方法(非接口中的方法)不能被代理。
三、JDK动态代理用到的类和接口
(1)Proxy类
通过JDK的java.lang.reflect.Proxy类实现动态代理,会使用其静态方法newProxyInstance(),依据目标对象、业务接口及调用处理器三者,自动生成一个动态代理对象。
public static newProxyInstance ( ClassLoader loader, Class<?>[] interfaces,InvocationHandler handler)
loader:目标类的类加载器,通过目标对象的反射可获取
interfaces:目标类实现的接口数组,通过目标对象的反射可获取
handler:调用处理器。
(2)Method类
反射用的类,用来进行目标对象的方法的反射调用。
method对象接住我们正在调用的方法sing(),show()
method——>sing(),show()
method.invoke();==>手工调用目标方法 sing(); show();invoke()方法的第二个参数为Method类对象,该类有一个方法也叫invoke(),可以调用目标方法。这两个invoke()方法,虽然同名,但无关。
public Object invoke ( Object obj, Object... args)
obj:表示目标对象
args:表示目标方法参数
args就是其上一层invoke方法的第三个参数,invoke方法的作用是:调用执行obj对象所属类的方法,这个方法由其调用者Method对象确定。在代码中,一般的写法为method.invoke(target, args);其中,method为上一层invoke方法的第二个参数。这样,即可调用了目标类的目标方法。
(3)InvocationHandler接口
它是实现代理和业务功能的,我们在调用时使用匿名内部实现。
InvocationHandler接口叫做调用处理器,负责完成调用目标方法,并增强功能。通过代理对象执行目标接口中的方法,会把方法的调用分派给调用处理器(InvocationHandler)的实现类,执行实现类中的invoke()方法,我们需要把功能代理写在invoke()方法中。
InvocationHandler此接口中只有一个invoke()方法。
InvocationHandler源码
package java.lang.reflect;
public interface InvocationHandler {
/**
* InvocationHandler是由代理实例的调用处理程序实现的接口。 每个代理实例都有一个关联的调用处
* 理程序。在代理实例上调用方法时,方法调用将被编码并调度到其调用处理程序的invoke方法
*/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}
在invoke方法中可以截取对目标方法的调用。在这里进行功能增强。Java的动态代理是建立在反射机制之上的。实现了InvocationHandler接口的类用于加强目标类的主业务逻辑。这个接口中有一个方法invoke(),具体加强的代码逻辑就是定义在该方法中的。通过代理对象执行接口中的方法时,会自动调用invoke()方法。
invoke()方法的介绍如下:
public Object invoke ( Object proxy, Method method, Object[] args)
A.proxy:代表生成的代理对象
B.method:代表目标方法
C.args:代表目标方法的参数
第一个参数proxy是jdk在运行时赋值的,在方法中直接使用,第二个参数后面介绍,第三个参数是方法执行的参数,这三个参数都是jdk运行时赋值的,无需程序员给出。
四、JDK动态代理实现
A.代理对象不需要实现接口
B.代理对象的生成是利用JDK包API中的Proxy类,动态的在内存中构建代理对象。
(1)定义业务接口
public interface Service {
//唱歌
void sing();
//展示年龄
String showAge (int age);
}
(2)接口实现——>刘德华+周润发
//目标对象
public class SuperStarLiu implements Service {
@Override
public void sing() {
System.out.println("刘德华正在唱歌");
}
@Override
public String showAge(int age) {
return "刘德华有" + age + "岁";
}
}
//目标对象
public class SuperSatZhou implements Service {
@Override
public void sing() {
System.out.println("周润发正在唱歌");
}
@Override
public String showAge(int age) {
return "周润发有" + age + "岁";
}
}
(3)JDK动态代理工厂类
本类中的方法(非接口中方法)不能被代理
public class ProxyFactory {
//类中成员变量声明为接口
public Service target;//目标对象
//传入目标对象,方法设计为接口
public ProxyFactory(Service target) {
this.target = target;
}
//调用处理程序,返回指定接口的代理类实例(动态代理对象)
public Object getAgent() {
// 处理代理实例(代理对象)上的方法调用并返回结果(目标对象)。
return Proxy.newProxyInstance(
target.getClass().getClassLoader(), //指定当前目标对象,使用类加载器获得
target.getClass().getInterfaces(),//获得目标对象实现的所有接口
new InvocationHandler() { //处理代理实例上的方法并返回调用结果
@Override
public Object invoke(
Object proxy, //代理对象的实例
Method method,//代理的目标对象的实现方法
Object[] args) throws Throwable { //代理的目标对象实现方法的参数
System.out.println("预订时间");
System.out.println("预订场地");
//目标对象通过调用反射自动执行自己的方法
Object returnValue = method.invoke(target, args);//sing(),show(args)
System.out.println("结算费用");
return returnValue;//返回目标对象执行方法的返回值
}
});
}
}
(4)junit代码测试JDK动态代理
@Test
public void test1() {
ProxyFactory proxyFactory = new ProxyFactory(new SuperSatZhou());
Service agent = (Service) proxyFactory.getAgent();
agent.sing();
}
@Test
public void test2() {
ProxyFactory proxyFactory = new ProxyFactory(new SuperSatZhou());
Service agent = (Service) proxyFactory.getAgent();
System.out.println(agent.showAge(25));
}
@Test
public void test3() {
ProxyFactory proxyFactory = new ProxyFactory(new SuperStarLiu());
Service agent = (Service) proxyFactory.getAgent();
System.out.println(agent.showAge(50));
System.out.println(agent.getClass());//动态代理类型:class com.sun.proxy.$Proxy2
}
补充:在业务接口Service中,可以根据需求增加业务功能,同时实现类也相应的重写方法,编写具体业务功能代码,而JDK代理工厂类不做任何改动,当调用运行时,会自动执行对应的方法,最终成为$Proxy类型的代理对象。
五、总结
仅自己学习记录,如有错误,敬请谅解~,谢谢~~~