动态代理
传统代理是一个接口2个子类,一个是真实主体类,另外一个是代理类,这样以来导致一个代理类只能为一个接口服务,这样设计明显不好。所以java 提供了动态代理类。
如果想要实现动态代理类,则必须采用 InvcationHandler 接口处理,此接口定义了一个invoke方法
/**
* @param proxy 代理的对象
* @param method 表示真实主体要使用的方法
* @param args 调用方法时要传递的参数
* @return 这个数据就是调用方法时返回的结果,
*/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
所有真实主体都需要返回一个代理类对象,而这个代理类对象由Proxy类完成,在Proxy 类中定义了以下方法
/**
* @param loader 返回目标对象的类加载器,读取要代理的类代码,重新实例化。
* @param interfaces 返回一个类实现的所有接口
* @param h 完成代理操作
* @return 要操作的代理对象
*/
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
实例:
1,创建核心代理类:
package cn.lyx.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* Created by ShayneLee on 2017/11/15
*/
public class DaoProxy implements InvocationHandler{
private Object target; // 要代理的对象信息
public Object bind(Object target) { // 需要由系统生成一个指定接口的代理类对象
this.target = target;
// 返回与当前传入对象结构相同的代理类对象
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
this.log(method.getName()); // 取得当前执行方法名称
Object retObj = method.invoke(this.target, args);
// 如果是更新则进行事务处理
if (method.getName().matches("do[a-zA-Z0-9]+")) {
commit();
}
return retObj;
}
public void log(String methodName) {
System.out.println("进行日志记录, 方法: " + methodName);
}
public void commit() {
System.out.println("事务提交");
}
}
测试类:
package cn.lyx.test;
import cn.lyx.dao.IUserDao;
import cn.lyx.dao.UserDaoImpl;
import cn.lyx.proxy.DaoProxy;
/**
* Created by ShayneLee on 2017/11/15
*/
public class ProxyDemo {
public static void main(String[] args) {
// 通过代理类获取主体对象
IUserDao iUserDao = (IUserDao) new DaoProxy().bind(new UserDaoImpl());
iUserDao.doCreate(null);
iUserDao.findByName("");
}
}
其他代码:
package cn.lyx.entity;
/**
* Created by ShayneLee on 2017/11/15
*/
public class User {
private String name;
private Integer age;
public void setAge(Integer age) {
this.age = age;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public String getName() {
return name;
}
@Override
public String toString() {
return age +":" +name;
}
}
package cn.lyx.dao;
import cn.lyx.entity.User;
/**
* Created by ShayneLee on 2017/11/15
*/
public interface IUserDao {
public void doCreate(User user);
public User findByName(String name);
}
/
package cn.lyx.dao;
import cn.lyx.entity.User;
/**
* Created by ShayneLee on 2017/11/15
*/
public class UserDaoImpl implements IUserDao{
@Override
public void doCreate(User user) {
System.out.println("创建用户");
}
@Override
public User findByName(String name) {
System.out.println("查询用户");
User user = new User();
user.setName("名字");
return user;
}
}
结果:
以上就完成了简单的动态代理模式。
CGLIB 处理代理
上述代码有个缺陷,用到了
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
使用这种代理类一定要传入接口,如果没有接口则会报错。
sf(www.sf.net, findjar.com) 提供第三方组件 —— cglib 包。
在上例代码中使用到 Proxy 类 ,InvocationHandler 接口, 但是在CGLIB 中不存在,而是提供以下:
- net.sf.cglib.proxy.Enhancer 类似 Proxy 功能,返回代理对象
- net.sf.cglib.proxy.MethodInterceptor 是一个处理代理操作的接口
- net.sf.cglib.proxy.MethodProxy 代替之前的Method 功能
例子:
首先引入 cglib 第三方组件 cglib-nodep-3.2.4.jar
package cn.lyx.test;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* Created by ShayneLee on 2017/11/16
*/
public class CGLIBDemo {
public static void main(String[] args) {
Hello hello = new Hello();
Enhancer enhancer = new Enhancer(); // 代理类对象
enhancer.setSuperclass(Hello.class); // 为代理类对象设置一个父类
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("*****你好*****");
return method.invoke(hello, args);
}
});
Hello retHello = (Hello) enhancer.create(); // 返回代理类对象
retHello.helloMethod();
}
}
class Hello{
public void helloMethod(){
System.out.println("Hello 你好");
}
}
运行结果:
完成了 cglib 的简单代理
参考: 李兴华-java 反射机制