Spring--AOP动态代理技术之jdk动态代理

1.什么是动态代理技术

Java中的动态代理,就是使用者使用的不是真实的对象,而是使用的一个代理对象,而这个代理对象中包含的就是真实的对象,代理对象就是不改变原有对象的功能方法的基础之上封装新的功能

动态代理不是在编译阶段产生的代理对象(开发者不同编写源代码),而是在JVM运SpringAOP使用代理技术两种
1,Java官方的JDK动态代理技术
2,CGLIB 第三方代理技术行中动态产生的

2.使用JDK动态代理

2.1.JDK动态代理API分析

2.1.1 java.lang.reflect.Proxy 类:

Java 动态代理机制生成的所有动态代理类的父类,它提供了一组静态方法来为一组接口动态地生成代理类及其对象。
主要方法
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler hanlder)
方法职责:为指定类加载器、一组接口及调用处理器生成动态代理类实例
参数:
loader :类加载器
interfaces : 被代理对象的接口
hanlder :代理执行处理器

返回:动态生成的代理对象

2.1.2java.lang.reflect.InvocationHandler接口:

public Object invoke(Object proxy, Method method, Object[] args)
方法职责:负责集中处理动态代理类上的所有方法调用
参数:
proxy :生成的代理对象
method :当前调用的真实方法对象
args :当前调用方法的实参

返回: 真实方法的返回结果

2.1.3 jdk动态代理操作步骤

① 实现InvocationHandler接口,创建自己增强代码的处理器。
② 给Proxy类提供ClassLoader对象和代理接口类型数组,创建动态代理对象。
③ 在处理器中实现增强操作。

具体创建步骤:

1)新建一个创建代理类的类,我们把它称为场所
2)在场所中拥有真实对象,一般是实现类,因为我们要用这个对象来获取接口
3)在场所中还需要拥有增强方法的类,例如事务管理器
4)在场所中,需要有一个getProxy的方法,该方法的返回类型设置为泛型,参数为Class cls,这样可以保证返回的代理类的类型同传入的一样,
5)在getProxy方法中,利用Proxy的静态方法newProxyInstance(类加载器,真实对象的接口,InvocationHandler)创建代理类
6)在newProxyInstance的第三个参数中重写InvocationHandler接口中的方法,在里面对真实对象的方法进行增强
7)在测试类中,根据场所中的getProxy方法获取代理对象,再调用代理对象的方法

/*
 * 
 * 此类是用于创建代理对象的对象(创建代理对象的场所)
 * 当前案例的代理对象的创建就在此类中完成
 * 
 * 
 * 创建代理对象的条件
 * 
 * 1,被代理的对象(真实对象),当前场景就是 UserServiceImpl
 * 
 * 2,要增强的功能,当前场景就是模拟的事务管理器
 * 
 * 
 * 创建代理对象
 * 
 * 通过一个方法返回代理对象,在方法内部完成代理对象的创建
 * 
 * 
 */

@Component
public class JdkDynamicProxyObjectHandler {

	
	/*
	 * 1,被代理的对象(真实对象),当前不要注入接口,因为当前JDK动态代理底层使用时接口产生代理对象
	 *  只有注入实现类才能获取对应的接口
	 *  如果直接注入接口,接口不可能获取接口的
	 */
	@Autowired
	private UserServiceImpl target;
	
	
	//2,要增强的功能,当前场景就是模拟的事务管理器
	@Autowired
	private TransactionManagerHandler txManager;
	
	
	
	//返回代理对象的方法
	public <T> T getProxyObject(Class<T> clz) {
		/*
		 * 使用JDK官方的 Proxy 类创建代理对象
		 * 
		 * 
		 * ClassLoader loader = null;
		 * 	类加载器,一个项目启动时候在JVM有且只有一个类加载器,主要用于从项目中加载资源等等(从相对路径)
		 *  获取类加载器
		 *  1,从当前线程获取
		 *  	ClassLoader loader = Thread.currentThread().getContextClassLoader();
		 *  2,任何一个类的字节码都可以获取
		 *  	ClassLoader loader = JdkDynamicProxyObjectHandler.class.getClassLoader();
		 * 	
			Class<?>[] interfaces = null;
		 *	 被代理对象的接口字节码(因为JDK底层是通过接口创建代理对象)	
		 *
			InvocationHandler h = null;
		 *	处理器,接口,开发者需要自己实现并在接口方法内部完成 代理对象增强的逻辑处理
		 * 
		 */
		
		ClassLoader loader = Thread.currentThread().getContextClassLoader();
		
		Class<?>[] interfaces = target.getClass().getInterfaces();
		
		//创建的代理对象
		Object newProxyInstance = Proxy.newProxyInstance(loader, interfaces, new InvocationHandler() {
			/**
			 * 在此方法中完成增强的逻辑
			 * 
			 * 1,在方法内部执行被代理对象的方法,并返回执行结果
			 * 2,在被代理对象方法执行之前,之后,异常,最终做增强(模拟的事务管理器的功能)
			 * 
			 * @param proxy 创建的代理对象
			 * @param method  被代理对象要执行的对应的方法
			 * @param args 被代理对象执行的对应的方法的参数
			 * @return 返回的是被代理对象方法执行的结果
			 * @throws Throwable
			 */
			public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
				
				Object result  =null;
				try {
					//开启事务
					txManager.begin();
					//执行被代理对象的方法
					result = method.invoke(target, args);
					//提交事务
					txManager.commit();
				} catch (Exception e) {
					//回滚事务
					txManager.rollback();
				}finally {
					//释放资源
					txManager.close();
				}
				return result;
			}
		});

测试类
在这里插入图片描述

2.1.4 jdk动态代理缺点

1)jdk底层是通过接口创建代理类的,没有接口就创建不了代理对象
2)不能指定哪些方法方法做增强,像toString,hashCode等Object的方法也会被增强
3)需要为每个对象创建代理类

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值