JDK动态代理

JDK动态代理是Java官方的代理

使用JDK官方的Proxy类创建代理对象

  1. 需要通过Proxy类创建代理对象
  2. 创建代理对象必须要一个代理处理类

JDK动态代理API分析

1、java.lang.reflect.Proxy 类

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

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

2、java.lang.reflect.InvocationHandler接口:

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

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


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

配置步骤

CustomerServiceImpl

package com.spring.service.impl;

import com.spring.service.CustomerService;

public class CustomerServiceImpl implements CustomerService{

	@Override
	public void insert() {
		System.out.println("添加客户");
	}

	@Override
	public void update() {
		System.out.println("更新客户");
	}

}

TransactionManagerHandler

package com.spring.utils;
/*
 * 此类模拟事务管理器(专门处理事务的类)
 * 
 * 提供,开启,提交,回滚,关闭事务相关操作的方法
 * 
 * 
 */
public class TransactionManagerHandler {

	public void begin() {
		System.out.println("开启事务");
	}
	public void commit() {
		System.out.println("提交事务");
	}
	public void rollback() {
		System.out.println("回滚事务");
	}
	public void close() {
		System.out.println("释放资源");
	}
}

JdkDymnaicProxyHandler

package com.spring.utils;

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

/*
 * 
 * 	此类是创建代理对象的类,最有一个终返回代理对象方法
 * 
 * ------------------------
 * 
 *    创建代理对象要注入相关条件(对象)
 * 1,被代理的对象
 * 		当前场景 UserService接口的实现类 UserServiceImpl 的对象
 * 2,要增强的功能
 * 		当前场景就是  模拟的事务管理器 TransactionManagerHandler
 * 
 * 	最终在创建代理对象的过程,将模拟事务管理器功能,增强到 被代理对象的每一个方法上面 (insert,update,delete...)
 * 
 * 3,提供一个返回代理对象的方法
 * 	在方法内部完成创建代理对象的过程
 * 
 * 
 * 
 */
public class JdkDymnaicProxyHandler {
	
	/*
	 * 	1, 被代理的对象,理论上应该是 UserService接口的实现类 UserServiceImpl 的对象
	 *  	实际一般使用超级父类  Object
	 */
	private Object target;
	
	/*
	 * 2 ,模拟事务管理器
	 * 		要在代理对象里面增强的功能
	 */
	private TransactionManagerHandler txManager;
	
	
	//3,提供一个返回代理对象的方法
	//在方法内部完成创建代理对象的过程
	public <T> T getProxyObject() {
		/*
		 * 
		 * 	使用JDK的动态代理创建代理对象
		 * 
		 * Proxy 类: 是java官方提供的创建动态代理对象类
		 * 
		 * 	创建代理对象的方法
		 * Object newProxyObject  = Proxy.newProxyInstance(loader, interfaces, h);
		 * 
		 *	 参数说明	
		 * 	ClassLoader loader;
		 * 		类加载器:类加载器作用,从当前项目的classpath路径下面可以加载各种资源
		 * 		一个应应用启动的时候在内存有且一个一个类加载器,启动项目JVM已经创建好了
		 * 		开发者只需要获取类加载器即可
		 *   方式一:通过当前线程获取		
		 * 	ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
		 *  方式二:通过任何一个类的字节码实例都可获取
		 *  ClassLoader classLoader = JdkDymnaicProxyHandler.class.getClassLoader();
		 * -------------------------------------------------
			Class<?>[] interfaces;
				被代理对象的接口字节码实例,(一个类可能实现多个接口,所以是数组类型)
			InvocationHandler h;
				执行处理器,创建代理对象中具体做功能增强的地方
				开发如果自己处理增强逻辑,需要自己此接口
		 */
		
		
		
		ClassLoader loader = JdkDymnaicProxyHandler.class.getClassLoader();;
		
		/*
		 * 
		 * Class<UserServiceImpl> clz = target.getClass();
		 * 
		 * Class<?>[] interfaces  = clz.getInterfaces();
		 * 
		 */
		//被代理对象的接口的字节码实例
		Class<?>[] interfaces  = target.getClass().getInterfaces() ;
		
		//Proxy创建的代理对
		Object newProxyObject  = Proxy.newProxyInstance(loader, interfaces, new InvocationHandler() {
			
			/**
			 * 此方法就是Java的Proxy创建代理对象以后,开发者在此方法中为创建代理对象的方法做增强的地方
			 *  如 :方法执行之前,之后,异常,最终 相关事务增强
			 *  
			 * @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);
					System.out.println("被代理对象的方法名:"+method.getName());
					System.out.println("被代理对象方法的参数:"+args[0]);
					System.out.println("被代理对象方法执行结果:"+result);
					//提交事务
					txManager.commit();
					
				} catch (Exception e) {
					//e.printStackTrace();
					//回滚事务
					txManager.rollback();
				}finally {
					txManager.close();
				}
				
				return result;
			}
		});
		
		return (T) newProxyObject;
	}
	
	
	public void setTarget(Object target) {
		this.target = target;
	}
	public void setTxManager(TransactionManagerHandler txManager) {
		this.txManager = txManager;
	}
}

applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
	
	
	<!-- 配置模拟的事务管理器 -->
	<bean id="MyTxManager" class="com.spring.utils.TransactionManagerHandler"/>
	
	
	<!-- 被代理对象:真实对象 -->
	<bean id="userService" class="com.spring.service.impl.UserServiceImpl"/>
	
	<!-- 被代理对象:真实对象二 -->
	<bean id="customerService" class="com.spring.service.impl.CustomerServiceImpl"/>
	
	
	<!-- 创建返回代理对象 的对象 -->
	<bean id="proxyHandler" class="com.spring.utils.JdkDymnaicProxyHandler">
		<!-- 注入真实对象 -->
		<property name="target" ref="customerService"/>
		
		<!-- 注入模拟的事务管理器 -->
		<property name="txManager" ref="MyTxManager"/>
	</bean>
	

</beans>

测试代码

package com.spring.test;

import static org.junit.Assert.fail;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.spring.service.CustomerService;
import com.spring.utils.JdkDymnaicProxyHandler;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class CustomerServiceTest {
	
	@Autowired
	private JdkDymnaicProxyHandler handler;

	@Test
	public void testInsert() {
		CustomerService customerService = handler.getProxyObject();
		customerService.insert();
	}

	@Test
	public void testUpdate() {
		fail("Not yet implemented");
	}

}

测试结果图

在这里插入图片描述

JDK动态代理的不足

1,JDK动态代理的对象必须要实现一个接口;-因为JDK动态代理是基于接口代理的
2,需要为每个对象创建代理对象;
3,动态代理的最小单位是类(所有类中的方法都会被处理/增加),查询方法不需要事务,可能不需要被代理
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值