一、动态代理
-
动态代理和静态代理角色都一样(抽象角色、真实角色、代理角色)。
-
动态代理的代理类是动态生成的,不是我们直接写好的。(静态代理是我们自己写了代理类,但是动态代理就不需要我们自己的写代理类了。)
-
动态代理分为:
- 基于接口的:JDK 动态代理
- 基于类:cglib
- 基于Java 字节码:Javassist
我们主要学习JDK 的动态代理(Spring AOP默认使用JDK动态代理)。
需要在JDK的API文档中去看看 InvocationHandler(接口)、Proxy(类) 。(在反射包reflect下)
二、租房案例
还是使用上一篇静态代理中的案例,不过这次使用的是动态代理!
对象:房东(Renter )、中介(Proxy)
出租事件:Rent接口的rent()方法,用于出租。
关系:中介(代理对象)可以代理房东(真实对象)租房子。
1.抽象角色
抽象角色:代理角色(代理人)和真实角色可以实现)
这里抽象角色为一个接口:出租方法,用于出租房屋。
/** 房东Host和代理人中介Proxy都可以实现出租Rent这件事情(方法) */
public interface Rent {
/** 出租房屋 */
void rent();
}
2.真实角色
真实角色:真实的角色,可以实现业务方法.
真实角色房东,可以实现出租房屋。房东仅仅只用关注出租房屋。
/** 房东:可以出租房屋的人 */
public class Renter implements Rent {
@Override
public void rent() {
System.out.println("房东出租房子。");
}
}
3.创建调用处理器
创建一个类并且实现InvocationHandler接口。
用这个类来生成代理实例。
/** 调用处理类实例:(每个代理实例都有一个关联的调用处理程序) */
public class MyInvocationHandler implements InvocationHandler {
/** 被代理的接口 */
private Rent rent;
public void setRent(Rent rent) {
this.rent = rent;
}
/** 真正生成代理类的方法:返回rent接口的代理类实例 */
public Object getProxy() {
// 参数解释:loader:类加载器来定义代理类。interfaces :代理类实现的接口列表。h:调度方法调用的调用处理函数(因为实现了InvocationHandler所以直接填this)
return Proxy.newProxyInstance(this.getClass().getClassLoader(), rent.getClass().getInterfaces(), this);
}
/**
* 处理代理实例,并返回结果。(处理代理实例上的方法调用并返回结果。)
* proxy:调用该方法的代理实例(代理类代理的真实代理对象com.sun.proxy.$Proxy0(生成的代理对象)
* method:我们所要调用某个对象真实的方法的Method对象
* args:指代代理对象方法传递的参数
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
before();
// 方法调用
Object result = method.invoke(rent, args);
after();
return result;
}
void before() {
System.out.println("----- 中介带你看房 -----");
}
void after() {
System.out.println("----- 中介带你签合同 -----");
}
}
4.测试
创建调用处理器,set置入需要代理的对象(房东),获取代理对象(中介)。最后代理对象(中介)执行出租方法。
/** 租客:需要租房子的人 */
public class Tenant {
/** 顾客去租房 */
public static void main(String[] args) {
// 创建调用处理器
MyInvocationHandler ih = new MyInvocationHandler();
// set 置入需要代理的对象(房东)
ih.setRent(new Renter());
// 获取代理对象(中介)
Rent proxy = (Rent) ih.getProxy();
// 代理对象,执行出租方法。
proxy.rent();
}
}
输出:
----- 中介带你看房 -----
房东出租房子。
----- 中介带你签合同 -----
三、真实业务案例
还是使用上一篇静态代理中的案例,不过这次使用的是动态代理!
需求:
增加业务日志输出功能:业务调用前需要输出调用的方法名,调用后需要输出返回值。
1.抽象角色
用户增删改查接口。
/** 用户数据访问层接口 */
public interface UserDao {
void ins();
void del();
void upd();
void sel();
}
2.真实对象
用户接口的实现类
public class UserDaoImpl implements UserDao {
@Override
public void ins() {
System.out.println("insert命令");
}
@Override
public void del() {
System.out.println("delete命令");
}
@Override
public void upd() {
System.out.println("update命令");
}
@Override
public void sel() {
System.out.println("select命令");
}
}
3.创建调用处理类
创建调用处理类
/** 调用处理类实例:(每个代理实例都有一个关联的调用处理程序) */
public class MyInvocationHandler implements InvocationHandler {
private UserDao userDao;
public void setUserDaoImpl(UserDao userDao) {
this.userDao = userDao;
}
/** 获取代理对象 */
public Object getProxy() {
return Proxy.newProxyInstance(this.getClass().getClassLoader(), userDao.getClass().getInterfaces(), this);
}
/** 处理代理实例,并返回结果。 */
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
log(method.getName());
Object result = method.invoke(userDao, args);
logReturnType(method.getReturnType().getName());
return result;
}
/** 日志 */
private void log(String name) {
System.out.println("[info]: ----- "+name + "()方法 -----");
}
/** 日志 */
private void logReturnType(String name) {
System.out.println("[info]: ----- 返回类型:"+name + " -----");
}
}
4.测试
创建调用处理类实例,set注入需要代理的对象(UserDaoImpl),获取代理对象,最后执行代理对象的插入方法
public class Test {
public static void main(String[] args) {
// 创建调用处理类实例
MyInvocationHandler ih = new MyInvocationHandler();
// set 置入需要代理的对象(UserDaoImpl)
ih.setUserDaoImpl(new UserDaoImpl());
// 获取代理对象(UserDaoImpl)
UserDao proxy = (UserDao) ih.getProxy();
// 代理对象,执行插入方法。
proxy.ins();
}
}
输出:
[info]: ----- ins()方法 -----
insert命令
[info]: ----- 返回类型:void -----
四、封装成通用类
将刚刚使用的两个MyInvocationHandler给封装成通用类。至此i,JDK的动态代理已结束,开始学习Spring 的AOP。
/** 调用处理类实例:(每个代理实例都有一个关联的调用处理程序) */
public class MyInvocationHandler implements InvocationHandler {
/** 目标:被代理的接口 */
private Object target;
public void setTarget(Object target) {
this.target = target;
}
/** 返回代理类实例 */
public Object getProxy() {
// 参数解释:loader:类加载器来定义代理类。interfaces :代理类实现的接口列表。h:调度方法调用的调用处理函数(因为实现了InvocationHandler所以直接填this)
return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
/** 处理代理实例,并返回结果。(处理代理实例上的方法调用并返回结果。) */
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 方法调用
Object result = method.invoke(target, args);
return result;
}
}
相关
我的该分类的其他相关文章,请点击:【Spring + Spring MVC + MyBatis】文章目录