一.分析(必须要求真实对象是有接口的)
1. java.lang.reflext.proxy 类:java 动态代理机制生成的所有动态代理类的父类,它提供了一组静态方法为一组接口动态地生成代理类及其对象
主要方法:public static Object newProxyInstance(ClassLoader loader, Class<?>[]interface, invocationHander hander)
方法职责:为指定类加载器,一组接口及调用处理器生成动态代理实例
参数
loader :类加载器,一般传递真实对象的加载器
interface :代理类需要实现的接口
hander:代理对象如何做增强
返回:创建的代理对象
2.java.lang.reflect.invocationHander接口:
public invoke(Object proxy, Method method,Object[] args)
方法职责:负责集中处理动态代理类上的所有方法调用
参数:
proxy:生成代理对象
methos:当前调用的真实方法对象
args:当前调用方法的实参
返回:真实方法的返回结果n
二.JDK 动态代理操作步骤:
1.创建一个代理对象
2.实现invocationHander接口
3.覆盖invoke(),为真实对象方法做增强的具体操作
代码演示:
package com.keen.proxy.tx;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
@SuppressWarnings("all")//忽略所有警告
public class TransactionManagerAdvice implements InvocationHandler{
private Object targer;//真实对象,即对谁做增强
private TransactionManager txManager;//事务管理器(模拟)
public void setTarger(Object targer) {
this.targer = targer;
}
public void setTxManager(TransactionManager txManager) {
this.txManager = txManager;
}
//创建一个代理对象
public <T> T getproxyObject() {
return (T) Proxy.newProxyInstance(targer.getClass().getClassLoader(),//loader类加载器,一般跟上真实对象的类加载器
targer.getClass().getInterfaces(),//真实对象所实现的接口(jdk动态代理必须要求真实对象有接口)
this);//如何做事务增强的对象因为继承了InvocationHandler,所以直接用this就可以了
}
@Override
//如何为真实对象的方法增强的具体操作
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object ret = null;
txManager.begin();
//调用真实对象的方法
try {
ret = method.invoke(targer, args);//调用对象真实的方法
txManager.commit();
} catch (Exception e) {
e.printStackTrace();
txManager.rollback();
}
return ret;
}
}
context.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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<!-- di注解解析器 -->
<!-- <context:annotation-config/> -->
<!--IOC注解解析器 -->
<!-- <context:component-scan base-package="com.keen.proxy"/> -->
<bean id = "employeeDAO" class = "com.keen.proxy.dao.EmployeeDAOimpl"/>
<!-- 事务管理器 -->
<bean id = "transactionManager" class = "com.keen.proxy.tx.TransactionManager"/>
<!-- 配置事务增强类 -->
<bean id = "transactionManagerAdvice" class = "com.keen.proxy.tx.TransactionManagerAdvice" >
<property name="txManager" ref ="transactionManager"/>
<property name="targer" >
<!-- 把employeeService作为内部bean -->
<bean class ="com.keen.proxy.service.IEmployeeServiceImpl">
<property name = "dao" ref = "employeeDAO"/>
</bean>
</property>
</bean>
</beans>
测试类
package com.keen.proxy;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import com.keen.proxy.domain.Employee;
import com.keen.proxy.service.IEmployeeService;
import com.keen.proxy.tx.TransactionManagerAdvice;
@SpringJUnitConfig
public class AutoTest {
@Autowired
private TransactionManagerAdvice advice;
@Test
void testSave() throws Exception {
//获取代理对象 class com.sun.proxy.$Proxy19
IEmployeeService service = advice.getproxyObject();
service.save(new Employee());
}
@Test
void testUpdate() throws Exception {
IEmployeeService service = advice.getproxyObject();
service.update(new Employee());
}
}
⚠️:其他涉及相关的类和上一篇静态代理的类一样的,只是动态代理不需要静态代理那个IEmployeeServiceProxy类了。我们用TransactionManagerAdvice 替代了。