动态代理
静态代理比较麻烦,每次出现一个被代理类就需要为他们编写静态代理类,而动态代理就可以适应各种复杂的情况。
媒婆(婚介所)JDK动态代理类
public class JDKMeipo implements InvocationHandler {
/**
* 需要被代理的类对象
*/
private Object target;
public Object getInstance(Object target) {
this.target = target;
Class<?> clazz = target.getClass();
return Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
before();
Object obj = method.invoke(this.target, args);
after();
return obj;
}
private void before(){
System.out.println("媒婆来了");
}
private void after(){
System.out.println("介绍完了");
}
}
被代理接口以及实现类
public interface Person {
void findLove();
}
public class Customer implements Person{
@Override
public void findLove() {
System.out.println("我的需求如下:");
System.out.println("1. 180cm");
System.out.println("2. 本地土著");
}
}
测试
@Test
public void test1() {
Person person = (Person) new JDKMeipo().getInstance(new Customer());
person.findLove();
}
结果:
媒婆来了
我的需求如下:
1. 180cm
2. 本地土著
介绍完了
jdk动态代理是根据interface接口代理的,需要实现InvocationHandler接口。
数据源动态路由
动态代理:
public class OrderServiceDynamicProxy implements InvocationHandler {
private Object target;
public Object getInstance(Object target){
this.target = target;
Class<?> clazz = target.getClass();
return Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
before(args[0]);
Object object = method.invoke(target,args);
after();
return object;
}
private void before(Object param){
try {
System.out.println("代理之前执行代码...参数取第一个,调用getCreateTime来获取年份");
SimpleDateFormat yearFormat = new SimpleDateFormat("yyyy");
Long time = (Long) param.getClass().getMethod("getCreateTime").invoke(param);
Integer dbRouter = Integer.valueOf(yearFormat.format(new Date(time)));
System.out.println("动态代理分配到【DB_"+dbRouter+"】数据源处理数据");
DynamicDataSourceEntry.set(dbRouter);
} catch (Exception e) {
e.printStackTrace();
}
}
private void after(){
System.out.println("代理执行之后代码...");
}
}
测试:
@Test
public void test() throws ParseException {
Order order = new Order();
SimpleDateFormat sdf = new SimpleDateFormat("yyy/MM/dd");
Date date = sdf.parse("2020/02/03");
order.setCreateTime(date.getTime());
IOrderService instance = (IOrderService) new OrderServiceDynamicProxy().getInstance(new OrderService());
instance.createOrder(order);
}
结果:
代理之前执行代码...参数取第一个,调用getCreateTime来获取年份
动态代理分配到【DB_2020】数据源处理数据
orderService创建订单
创建新order
代理执行之后代码...
小结
可以很明显看出来,上面的动态代理代码并不是很灵活,因为硬性规定是通过实体的getCreateTime()来获取相关参数,其实可以通过注解等形式来做的,这里不做扩展。