java代理模式之jdk动态代理详解(超详细)

代理模式:

代理是基本的设计模式之一,它为你提供额外的或者不同的操作,而插入的用来代理"实际"对象的对象.这些操作通常涉及与"实际"对象的通信,因此代理通常充当着中间人的角色.

动态代理

动态代理是在实现阶段不用关心代理类,而在运行阶段才指定哪一个对象.
动态代理的优点:

  • 职责清晰
    真实的角色就是实现实际的业务逻辑,不用关心其他非本职责的事务,通过后期的代理完成一件完成事务,附带的结果就是编程简洁清晰。
  • 代理对象可以在客户端和目标对象之间起到中介的作用,这样起到了中介的作用和保护了目标对象的作用。也就是可以在不修改目标对象的基础上增强功能.
  • 高扩展性,可以给你需要的方法添加你需要的功能.

基于jdk实现动态代理:

在jdk的api中提供了java.lang.reflect.Proxy它可以帮助我们完成动态代理创建
注意:在java中使用Proxy来完成动态代理对象的创建,只能为目标实现了接口的类创建代理对象。
动态代理是在内存中直接生成代理对象。
在这里插入图片描述继续看api:
在这里插入图片描述一般我们使用这个方法来构造proxy对象,其中需要三个参数:

  1. ClassLoader loader:

在这里插入图片描述 翻译过来就是: 每个Class对象都包含对定义它的ClassLoader的引用。 数组类的类对象不是由类加载器创建的,而是根据Java运行时的需要自动创建的。 Class.getClassLoader()返回的数组类的类加载器与其元素类型的类加载器相同; 如果元素类型是基本类型,则数组类没有类加载器。 所以只要我们需要代理的对象不是数组,就可以用Class对象的getClassLoader()获取ClassLoader 对象;

  1. Class<?>[] interfaces:

在这里插入图片描述在class类里面有这个方法,可以直接获取,这个类代表的是目标对象实现的接口

  1. InvocationHandler h:
    点进去发现这是一个接口,有一个未实现的invoke(…)方法
    在这里插入图片描述
    在这里插入图片描述也就是说,这里需要传入的对象是需要实现这个接口的,并且需要完成这个invoke()方法,下面解释下这个方法里面的三个参数:
  • 参数一:Object proxy, ,这个就是我们要代理的对象

  • 参数二:Method method:我们需要访问的目标行为,也就是需要调用的方法

  • 参数三:Object[] args:调用行为的时候需要的参数

这个方法的主要作用是,当我们通过代理对象调用行为时,来控制目标行为是否可以被调用。
下面用代码进行实现:

//接口
public interface IUserService {
	public String addUser(String username,String password);
}
//实现类
public class UserServiceImpl implements IUserService {
	@Override
	public String addUser(String username, String password) {
		System.out.println("添加用户:" + username + "   " + password);
		return "hello " + username;
	}
}

现在我们要写一个代理类进行UserServiceImpl 的代理了:

public class UserServiceProxy implements InvocationHandler {
    // 目标对象
    private Object target;
    public UserServiceProxy(Object target) {
        this.target = target;
    }
    // 作用:创建代理对象
    public Object createProxy() {
        ClassLoader loader = target.getClass().getClassLoader();
        Class[] interfaces = target.getClass().getInterfaces();
        return Proxy.newProxyInstance(loader, interfaces, this);
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println(method);
        System.out.println(Arrays.asList (args));
        System.out.println("方法调用之前");
        Object result = method.invoke (target,args);
        System.out.println("方法调用之后");
        return result;
    }
}

接下来写一个测试类:

public class Test {
    public static void main(String[] args) {
        //需要代理的对象
        IUserService userservice = new UserServiceImpl ();
        //创建代理类
        UserServiceProxy up =  new UserServiceProxy(userservice);
        IUserService proxy = (IUserService) up.createProxy ();
        //使用代理类进行方法增强
        String s = proxy.addUser ("tom", "123");
        System.out.println("s: " + s);
    }
}

输出结果:
在这里插入图片描述
下面分析下输出:
第一个输出的是method对象,它指向的是IUserService.addUser,第二个是invoke()里面的第三个参数,其实就是我们使用代理对象时候用到的参数(第一个参数一般不使用),然后在addUser ()方法前后我们也将我们自定义的内容加进去了,而且还获得了方法调用的返回值.

总结:

  1. 动态代理是在实现阶段不用关心代理类,而在运行阶段才指定哪一个对象的一种代理方法。
  2. jdk的动态代理方式是使用Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)方法产生代理对象,第三个参数需要代理类实现InvocationHandler 接口,并实现invoke()方法,最后使用代理类进行方法的增强.
  3. 在开发中,我们使用动态代理可以完成性能监控,权限控制,日志记录等操作,spring的AOP有一部分是使用jdk的动态代理实现的.
  • 8
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值