在看动态代理解决两个案例之前,请先看链接VCR
《java代理》2分钟动画_哔哩哔哩_bilibili
一.动态代理-精致小案例
需求分析
传统方法
就是定义一个接口,然后实现类去实现规定的run方法
缺点:代码很冗余,有一些运行前和运行后的代码都给了实现类,难以管理
动态代理方法
使用动态代理,利用反射机制,根据方法决定调用哪个对象的方法
添加VehicleProxyProvider类
package me;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* @version 1.0
* VehicleProxyProvider 该类可以返回一个代理对象.
*/
public class VehicleProxyProvider {
//定义一个属性
//target_vehicle 表示真正要执行的对象
//该对象实现了Vehicle接口
private Vehicle target_vehicle;
//构造器
public VehicleProxyProvider(Vehicle target_vehicle) {
this.target_vehicle = target_vehicle;
}
//编写一个方法,可以返回一个代理对象, 该代理对象可以通过反射机制调用到被代理对象的方法
public Vehicle getProxy() {
//得到类加载器
ClassLoader classLoader =
target_vehicle.getClass().getClassLoader();
//得到要代理的对象/被执行对象 的接口信息,底层是通过接口来完成调用
Class<?>[] interfaces = target_vehicle.getClass().getInterfaces();
//创建InvocationHandler 对象
//因为 InvocationHandler 是接口,所以我们可以通过匿名对象的方式来创建该对象
/**
*
* public interface InvocationHandler {
* public Object invoke(Object proxy, Method method, Object[] args)
* throws Throwable;
* }
* invoke 方法是将来执行我们的target_vehicle的方法时,会调用到
*
*/
InvocationHandler invocationHandler = new InvocationHandler() {
/**
* invoke 方法是将来执行我们的target_vehicle的方法时,会调用到
* @param o 表示代理对象
* @param method 就是通过代理对象调用方法时,的哪个方法 代理对象.run()
* @param args : 表示调用 代理对象.run(xx) 传入的参数
* @return 表示 代理对象.run(xx) 执行后的结果.
* @throws Throwable
*/
@Override
public Object invoke(Object o, Method method, Object[] args)
throws Throwable {
System.out.println("交通工具开始运行了....");
//这里是我们的反射基础 => OOP
//method 是?: public abstract void com.hspedu.spring.proxy2.Vehicle.run()
//target_vehicle 是? Ship对象
//args 是null
//这里通过反射+动态绑定机制,就会执行到被代理对象的方法
//执行完毕就返回
Object result = method.invoke(target_vehicle, args);
System.out.println("交通工具停止运行了....");
return result;
}
};
/*
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
老师解读
1. Proxy.newProxyInstance() 可以返回一个代理对象
2. ClassLoader loader: 类的加载器.
3. Class<?>[] interfaces 就是将来要代理的对象的接口信息
4. InvocationHandler h 调用处理器/对象 有一个非常重要的方法invoke
*/
Vehicle proxy =
(Vehicle) Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
return proxy;
}
}
最重要的代码就是 :
Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
这是提供最后代理对象实例的方法:参数有三:
@你要求代理对象的类加载器
@你要求代理对象的接口信息
@以及调用处理器
底层是用反射机制来实现的。
测试方法:
public class VehicleProxyTest {
@Test
public void test01()
{
Vehicle vehicle = new Ship();
//传入我们需要代理的对象
VehicleProxyProvider vehicleProxyProvider = new VehicleProxyProvider(vehicle);
//获取代理对象
Vehicle proxy = vehicleProxyProvider.getProxy();
//通过代理对象执行对应的run()方法
proxy.run();
}
}
以及真正的运行结果:
真正解析这个代码
所谓的这个代理,就可以将我们的Vehicle接口看做是一个老板。我们的car类和ship类就是员工。现在老板给这两个员工一个run的工作,但是因为在run工作的前后他们都要输出相同的一句话。这个输出同一句话没必要让每个员工都写一遍,于是就把这个输出同一句话的事情交给了一个代理对象,帮我们输出这句话。代理对象就是老板的助理。
这个代码提供代理对象的类:
当你调用proxy.run()方法的时候:会进入到调用器InvocationHandler的invoke方法去
这个调用器中的Object o就是你传入的ship对象,method就是run()方法,arg就是run()里面的参数。
Object result = method.invoke(target_vehicle, args);
方法.invoke(对象)这是反射调用对象ship的run()方法。返回一个结果,
可以自己去debug一下这个代码。
二.动态代理的深入[横切关注点]
需求分析
传统的方法
定义接口:
package proxy;
/**
* @version 1.0
* 接口
*/
public interface SmartAnimalable {
//求和
float getSum(float i, float j);
//求差
float getSub(float i, float j);
}
传统的实现子类
package proxy;
/**
* @version 1.0
*/
public class SmartDog implements SmartAnimalable {
@Override
public float getSum(float i, float j) {
//System.out.println("日志-方法名-getSum-参数 " + i + " " + j);
float result = i + j;
System.out.println("方法内部打印result = " + result);
//System.out.println("日志-方法名-getSum-结果result= " + result);
return result;
}
@Override
public float getSub(float i, float j) {
//System.out.println("日志-方法名-getSub-参数 " + i + " " + j);
float result = i - j;
System.out.println("方法内部打印result = " + result);
//System.out.println("日志-方法名-getSub-结果result= " + result);
return result;
}
}
结果:
动态代理的方法
MyProxyProvider
package proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
/**
* @version 1.0
* 可以返回一个动态代理对象, 可以执行SmartDog对象的方法
*/
public class MyProxyProvider {
//定义我们要执行的目标对象, 该对象需要实现SmartAnimalable
private SmartAnimalable target_obj;
//构造器
public MyProxyProvider(SmartAnimalable target_obj) {
this.target_obj = target_obj;
}
//方法, 可以返回代理对象,该代理对象可以执行目标对象
public SmartAnimalable getProxy() {
//1. 先到的类加载器/对象
ClassLoader classLoader = target_obj.getClass().getClassLoader();
//2. 得到要执行的目标对象的接口信息
Class<?>[] interfaces = target_obj.getClass().getInterfaces();
//3. 创建InvocationHandler
InvocationHandler invocationHandler = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = null;
try {
System.out.println("方法执行前-日志-方法名-" + method.getName() + "-参数 "
+ Arrays.asList(args)); //这里从AOP看,就是一个横切关注点-前置通知
//使用反射调用方法
result = method.invoke(target_obj, args);
System.out.println("方法执行正常结束-日志-方法名-" + method.getName() + "-结果result= "
+ result);//从AOP看, 也是一个横切关注点-返回通知
} catch (Exception e) {
e.printStackTrace();
//如果反射执行方法时,出现异常,就会进入到catch{}
System.out.println("方法执行异常-日志-方法名-" + method.getName()
+ "-异常类型=" + e.getClass().getName());//从AOP看, 也是一个横切关注点-异常通知
} finally {//不管你是否出现异常,最终都会执行到finally{}
//从AOP的角度看, 也是一个横切关注点-最终通知
System.out.println("方法最终结束-日志-方法名-" + method.getName());
}
return result;
}
};
//创建代理对象
SmartAnimalable proxy =
(SmartAnimalable)Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
return proxy;
}
}
Test方法
@Test
public void smartDogTestByProxy() {
SmartAnimalable smartAnimalable = new SmartDog();
MyProxyProvider myProxyProvider =
new MyProxyProvider(smartAnimalable);
//我们返回了代理对象
SmartAnimalable proxy =
myProxyProvider.getProxy();
proxy.getSum(10, 2);
System.out.println("====================");
proxy.getSub(10, 2);
}