JDK动态代理是Java官方的代理
使用JDK官方的Proxy类创建代理对象
- 需要通过Proxy类创建代理对象
- 创建代理对象必须要一个代理处理类
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,动态代理的最小单位是类(所有类中的方法都会被处理/增加),查询方法不需要事务,可能不需要被代理