java 反射机制-学习笔记(8)

 动态代理

传统代理是一个接口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 例子

完成了 cglib 的简单代理

参考: 李兴华-java 反射机制

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值