概念
代理模式是基本的设计模式之一,它是开发者为了提供额外的或不同的操作,而插入的用来代替“实际”对象的对象。这些操作通常涉及与“实际”对象的通信,因此代理通常充当着中间人的角色。
Java动态代理比代理的思想更进一步,因为它可以动态地创建代理并动态地处理对代理方法的调用。在动态代理上所做的所有调用都会被重定向到单一的调用处理器(InvocationHandler)上,调用处理器的工作是揭示调用的类型并确定相应的策略。
Java动态代理实现机制采用了反射的思想,有关于反射的基础知识,可以参见博客Java发射机制浅析。
原理
Spring核心AOP实现技术之一是采用Java动态代理机制,权限认证、日志以及事务管理都可以采用动态代理,使用动态代理机制可以减少代码重复,降低系统耦合度。Java动态代理API位于java.lang.reflect包下,实现动态代理主要涉及以下两个关键步骤:
1.实现InvocationHandler接口
InvocationHandler接口仅定义了一个方法。
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
proxy:代理对象
method:被代理类方法对象
args:被代理方法参数数组
proxy参数表示代理对象,以防开发者需要区分请求的来源,但是在许多情况下,开发者并不关心这一点。InvocationHandler通常需要持有被代理对象的引用,在动态代理上所做的所有调用都会被重定向到InvocationHandler接口的invoke方法上。在invoke方法内部调用被代理对象的method方法,开发者可以在方法调用前后加上需要的逻辑。如果只是想对某些方法进行代理,开发者可以在invoke方法内添加相应的过滤条件,通过method参数可以获取方法本身的很多信息。
2.通过Proxy创建动态代理类实例
Proxy是所有动态代理类的父类,并提供一个静态方法newProxyInstance负责创建动态代理类的实例。
public static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)
throws IllegalArgumentException
loader:类加载器(通常可以从已经被加载的对象中获取其类加载器)
interfaces:代理类需要实现的接口列表(通常使用被代理类实现的接口列表)
h:InvocationHandler接口的一个实现
newProxyInstance方法会根据传入的接口列表interfaces在虚拟机中动态的生成一个Proxy的子类,并实现了传入的接口列表interfaces的所有方法,然后返回该类的一个实例。因此返回的对象能够转型到传入的任意一个接口,通过该对象对接口内所有方法的调用都会重定向到第三个参数h的invoke方法。
Java动态代理底层原理实现比较复杂。总而言之,是根据newProxyInstance方法传入的类加载器和接口,生成代理类的二进制字节码,再利用反射机制创建代理类的实例,在代理类的内部对被代理类方法的调用都会重定向到InvocationHandler中的invoke方法,在invoke方法内再对被代理方法的调用进行封装预处理,加上开发者自己的逻辑。
应用
下面演示两个简单的示例:方法性能监测和日志管理
实体类
public class User {
private String name;
public User(String name) {
super();
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
接口
public interface UserDao {
void addUser(User user);
void deleteUser(String name);
void updateUser(String name);
}
实现类
public class UserDaoImpl implements UserDao {
@Override
public void addUser(User user) {
System.out.println("add user named " + user.getName() + "...");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public void deleteUser(String name) {
System.out.println("delete user named " + name + "...");
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public void updateUser(String name) {
System.out.println("update user named " + name + "...");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
其实做为一个开发者,有一个学习的氛围跟一个交流圈子特别重要这里我推荐一个Java交流群664389243,不管你是小白还是大牛欢迎入驻,大家一起交流成长。