欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

动态代理-JDK动态代理

程序员文章站 2022-04-19 16:30:19
...

代理是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个对象的访问。代理类负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理。为了保持行为的一致性,代理类和委托类通常会实现相同的接口,所以在访问者看来两者没有丝毫的区别。通过代理类这中间一层,能有效控制对委托类对象的直接访问,也可以很好地隐藏和保护委托类对象,同时也为实施不同控制策略预留了空间,从而在设计上获得了更大的灵活性。Java 动态代理机制以巧妙的方式近乎完美地实践了代理模式的设计理念。

InvocationHandler:
每一个动态代理类都必须要实现InvocationHandler这个接口,并且每个代理类的实例都关联一个handler,当调用代理对象中的任意方法的时候这个方法的调用就会被转发到InvocationHandler接口中的invoke方法来进行调用
invoke是InvocationHandler中唯一的方法
Object invoke(Object proxy, Method method, Object[] args) throws Throwable
proxy:为当前的代理对象
method:为当前调用的方法
args:为当前方法所需要的参数
Proxy:
proxy这个类的作用是用来动态生成代理对象的类,其中我们用到方法是newProxyInstance()方法:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,  InvocationHandler h)  throws IllegalArgumentException
这个方法的作用就是得到一个动态代理对象
loader:一个ClassLoader对象,定义了由哪个ClassLoader对生成的代理对象进行加载
interfaces:一个接口对象记数组,表示的是为我们将要创建代理对象提供一组接口,有了这些接口创建出来的这个代理对象就会声明为已经实现了该接口,这样就能调用这组接口中的方法了
invocationHandler:表示当前这个动态代理对象在调用方法时会关联到哪一个 调用执行器上(InvocationHandler)
在程序运行时期通过java的反射机制去生成一个代理类,但是在生成这个类的条件是程序必须得提供一组interface接口给它,生成的代理类会声明为已经实现了提供的这些接口的方式创建,这样的话我们就可以把代理类中的实例当做为提供的任何一个接口来使用(可以强转为相应的接口类型),即便是这样代理类终究是代理类没有什么实质的操作,所有还有提供一个InvocationHandler 在调用任何一个实例方法时会有这个invocationHandler来接管实际的操作

 package com.mybatis.excample.dynamicProxy.javaJdk;

/**
 * 需要动态代理的接口
 */
public interface JdkUserService {

	void addUser(String userId, String userName);

}
package com.mybatis.excample.dynamicProxy.javaJdk;

/**
 * 被代理的lei
 */
public class JdkUserServiceImpl implements JdkUserService {
	@Override
	public void addUser(String userId, String userName) {
		System.out.println("执行用户添加--用户id为:" + userId + "用户名称为:" + userName);
	}

}
package com.mybatis.excample.dynamicProxy.javaJdk;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * 自定义 InvocationHandler实现类
 */
public class JdkProxy implements InvocationHandler {
 //持有一个实现了接口的实现类 就需要被代理的那个类的对象(即委托类)
	private Object target;

	/**
	 * 根据输入的 委托类 返回 此类的代理对象
	 *		这是很重要的一步,就是通过target来绑定委托对象的 然后生成对应的代理类返回
	 * @param target 需要代理的 接口实现类
	 * @return  返回代理对象
	 */
	public Object JdkProxy(Object target) {
		this.target = target;
   //此处的参数为 委托类的类加载器,委托类的接口数组,自定义InvocationHandler(即本类)
		return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
	}

	/**
 当代理类中的任意方法被调用时 会转发至本方法来执行代理类对应的委托类中的方法
	 * @param proxy  被代理的对象
	 * @param method 要调用的方法
	 * @param args   方法所需要的参数
	 * @throws Throwable
	 * @return 返回方法执行完后的结果
	 */
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		Object result = null;
		/*
		before: 这里可以在 调用之前做操作
		 */
		result = method.invoke(target, args);
		/**
		 * 这里可以在方法调执行完后 执行操作
		 */
		return result;
	}
}
package com.mybatis.excample.dynamicProxy.javaJdk;

/**
 * 测试入口
 */
public class JdkClient {
	public static void main(String[] args) {
		JdkProxy proxy = new JdkProxy();
		//获取代理对象
		JdkUserService userService = (JdkUserService) proxy.JdkProxy(new JdkUserServiceImpl());
		//执行代理方法
		userService.addUser("8859-1", "编码名称");
		System.out.println("执行完成");
		System.exit(0);//正常终止 虚拟机

	}

}