一.动态代理(需要定义接口)
动态代理类是在程序运行期间由JVM通过反射等机制动态的生成的,所以不存在代理类的字节码文件。
代理对象和真实对象的关系是在程序运行事情才确定的。
JDK动态代理API分析:
1、java.lang.reflect.Proxy 类:
Java 动态代理机制生成的所有动态代理类的父类,它提供了一组静态方法来为一组接口动态地生成代理类及其对象。
主要方法:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler hanlder)
方法职责:为指定类加载器、一组接口及调用处理器生成动态代理类实例
参数:
loader :类加载器778776
interfaces :模拟的接口
hanlder :代理执行处理器
返回:动态生成的代理对象
2、java.lang.reflect.InvocationHandler接口:
public Object invoke(Object proxy, Method method, Object[] args)
方法职责:负责集中处理动态代理类上的所有方法调用
参数:
proxy :生成的代理对象
method :当前调用的真实方法对象
args :当前调用方法的实参
返回: 真实方法的返回结果
3.JDK动态代理操作步骤
① 实现InvocationHandler接口,创建自己增强代码的处理器。
② 给Proxy类提供ClassLoader对象和代理接口类型数组,创建动态代理对象。
二.JDK动态代理需要注意的几点:
JDK动态代理:
1,代理的对象必须要实现一个接口;
2,需要为每个对象创建代理对象;
3,动态代理的最小单位是类(所有类中的方法都会被处理);
三.JDK动态代理拓展及其常用的方法:
1,JAVA动态代理是使用java.lang.reflect包中的Proxy类与InvocationHandler接口这两个来完成的。
2,要使用JDK动态代理,必须要定义接口。
3,JDK动态代理将会拦截所有pubic的方法(因为只能调用接口中定义的方法),这样即使在接口中增加了新的方法,不用修改代码也会被拦截。
4,如果只想拦截一部分方法,可以在invoke方法中对要执行的方法名进行判断
四.JDK动态代理代码示例
接口及其实现类
public interface IEmployeeService {
void save(Employee e);
void update(Employee e);
}
@Service("target")
public class EmployeeServiceImpl implements IEmployeeService{
@Autowired
private IEmployeeDao employeeDao ;
@Override
public void save(Employee e) {
employeeDao.save(e);
}
@Override
public void update(Employee e) {
employeeDao.update(e);
}
}
事物管理器示例
@Component("txManager")
public class TransactionManager {
public void begin(){
System.out.println("事物开启。。。。。");
}
public void commit(){
System.out.println("事物提交。。。。。");
}
public void rollback(){
System.out.println("事物回滚。。。。。");
}
}
JDK动态代理类(通用)
@Component("jdkProxy")
public class TransactionManagerHandler implements java.lang.reflect.InvocationHandler {
@Autowired
@Qualifier("target")
private Object target; //真实对象(被代理的对象):在此处指的是EmployeeServiceImpl
@Autowired
private TransactionManager txManager;
// 创建一个代理对象
public <T>T getProxyObject(){
Object obj = Proxy.newProxyInstance(target.getClass().getClassLoader(), //类加载器
target.getClass().getInterfaces(), // 真实对象实现的接口:EmployeeServiceImpl的接口
this); // 增强的对象
return (T)obj;
}
// 在真实对象上做增强操作
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object obj = null;
txManager.begin();
try {
obj = method.invoke(target, args); // 真实对象中的方法
txManager.commit();
} catch (Exception e) {
txManager.rollback();
e.printStackTrace();
}
return obj;
}
}
配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
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
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
">
<!-- 解析autowired,resource,qualifier-->
<context:annotation-config />
<!--去哪些包下面去扫描组件-->
<context:component-scan base-package="com.shenzhenair.day02.common" />
<context:component-scan base-package="com.shenzhenair.day02.jdk_proxy" />
</beans>
测试类
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:com/shenzhenair/day02/jdk_proxy/jdkProxy.xml")
public class JDKProxyTest {
@Autowired
@Qualifier("jdkProxy")
private TransactionManagerHandler handler;
//com.sun.proxy.$Proxy15
@Test
public void testSave(){
// 获得代理对象
IEmployeeService proxyObject = handler.getProxyObject();
System.out.println(proxyObject.getClass());
proxyObject.save(new Employee());
}
}
运行结果