一个动态代理的小demo
对保存数据这一行为模拟添加事务管理
动态代理的特点
进行代理的对象不需要实现接口,但是要求被代理的目标对象必须实现接口,否则不能使用动态代理。先给出一个接口:IUserDao
接口:IUserDao
package com.DynamicProxy;
public interface ISaveInfoDao {
public void save();
}
需要进行代理的目标对象
package com.DynamicProxy;
//目标对象
public class SaveInfoDao implements ISaveInfoDao {
@Override
public void save() {
System.out.println("保存数据");
}
}
java动态代理机制中有两个重要的类和接口
InvocationHandler
(接口)和Proxy
(类),这一个类Proxy和接口InvocationHandler是实现动态代理的核心。
每一个动态代理类的调用处理程序都必须实现InvocationHandler接口,并且每个代理类的实例都关联到了实现该接口的动态代理类调用处理程序中,当我们通过动态代理对象调用一个方法时候,这个方法的调用就会被转发到实现InvocationHandler接口类的invoke方法来调用
定义一个代理类的调用处理程序,每个代理类的调用处理程序都必须实现InvocationHandler接口,实现如下:
package com.DynamicProxy;
import java.lang.reflect.Method;
import java.lang.reflect.InvocationHandler;
public class SelDefHandler implements InvocationHandler {
//需要代理的目标对象
private Object target;
//构造函数,给目标对象赋值
public SelDefHandler(Object obj) {
this.target = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//代理对象相较于目标对象多出的行为(根据业务需求自定义)
System.out.println("开启事务");
//执行目标对象方法
Object returnValue = method.invoke(target, args);
//代理对象相较于目标对象多出的行为(根据业务需求自定义)
System.out.println("提交事务");
return returnValue;
}
}
或者通过代理对象工厂产生代理对象
package com.DynamicProxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//动态代理对象
public class ProxyFactory {
//代理类中的真实对象(即需要代理的目标对象,发生行为的真实对象)
private Object target;
//构造函数,给我们的目标对象赋值
public ProxyFactory(Object target) {
this.target = target;
}
/*
返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序。
static Object newProxyInstance(ClassLoader loader, //指定当前目标对象使用类加载器
Class<?>[] interfaces,//目标对象实现的接口的类型
InvocationHandler h //事件处理器
)
在代理实例上处理方法调用并返回结果。
Object invoke(Object proxy, Method method, Object[] args)
*/
// 为目标对象生成代理对象
public Object getProxyInstance() {
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("开启事务");
// 执行目标对象方法
Object returnValue = method.invoke(target, args);
//代理对象相较于目标对象多出的行为(根据业务需求自定义)
System.out.println("提交事务");
return returnValue;
}
});
}
}
测试
package com.DynamicProxy;
import org.junit.Test;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
public class TestProxy {
@Test
//直接生成代理对象
public void testDynamicProxyDirect() {
//需要代理的目标对象,核心行为真实执行者
ISaveInfoDao target1 = new SaveInfoDao();
//代理对象的调用处理程序,我们将要代理的真实对象传入代理对象的调用处理的构造函数中,最终代理对象的调用处理程序会调用真实对象的方法
InvocationHandler handler = new SelDefHandler(target1);
/**
通过Proxy类的newProxyInstance方法创建代理对象,方法中的参数如下:
第一个参数:people.getClass().getClassLoader(),使用handler对象的classloader对象来加载我们的代理对象
第二个参数:people.getClass().getInterfaces(),这里为代理类提供的接口是真实对象实现的接口,这样代理对象就能像真实对象一样调用接口中的所有方法
第三个参数:handler,我们将代理对象关联到上面的InvocationHandler对象上
*/
ISaveInfoDao proxy1 = (ISaveInfoDao)Proxy.newProxyInstance(target1.getClass().getClassLoader(),
target1.getClass().getInterfaces(),
handler);
System.out.println(target1.getClass());
System.out.println(proxy1.getClass());
proxy1.save();
}
@Test
//通过代理工厂产生代理对象
public void testDynamicProxyByFactory (){
//需要代理的目标对象
ISaveInfoDao target = new SaveInfoDao();
ISaveInfoDao proxy = (ISaveInfoDao) new ProxyFactory(target).getProxyInstance();
System.out.println(target.getClass()); //输出目标对象信息
System.out.println(proxy.getClass()); //输出代理对象信息
proxy.save(); //执行代理方法
}
}
运行结果
参考博文:
https://segmentfault.com/a/1190000011291179
https://blog.csdn.net/yaomingyang/article/details/80981004