特点
:无侵入式的给代码增加额外的功能。
在Java中,动态代理是一种机制,允许在运行时创建一个代理对象来代替原始对象,并可以
在代理对象的方法执行前后追加额外的逻辑
。动态代理是通过Java的反射机制
实现的。
动态代理常用于在不修改原始类的情况下,增加额外的功能或在方法执行前后进行一些操作,比如日志记录、性能统计、事务管理等。
动态代理主要涉及
两个关键接口:InvocationHandler和Proxy
。
InvocationHandler负责实现代理对象的方法逻辑,而Proxy则用于创建代理对象。
使用动态代理,需要创建一个实现了InvocationHandler接口的类来处理代理对象的方法调用。
在InvocationHandler接口的invoke方法中,可以对原始对象的方法进行增强
。
然后,通过Proxy类的静态方法newProxyInstance来创建代理对象,同时指定要代理的接口类型和InvocationHandler对象。
最后,通过代理对象来调用方法,实际上会调用InvocationHandler的invoke方法
。
动态代理的优点是可以在不修改原始类的情况下,增加或改变其行为
。
它具有较高的灵活性和可扩展性,可以应用于各种场景,如AOP编程、远程方法调用
等。
①
Proxy
提供了为对象产生代理对象的方法:
public static ObjectnewProxyInstance
(ClassLoaderloader
,Class<?>[ ]interfaces
,InvocationHandlerh
)
参数一:用于指定用哪个类加载器,去加载生成的代理类
参数二: 指定接口,这些接口用于指定生成的代理长什么,也就是有哪些方法
参数三:用来指定生成的代理对象要干什么事情
编写一个明星行为接口Star:
public interface Star {
//想要被代理的方法写在接口当中
//唱歌
public abstract String sing(String name);
//跳舞
public abstract void dance();
}
创建一个BigStar类实现Star接口,重写方法:
public class BigStar implements Star {
private String name;
public BigStar() {
}
public BigStar(String name) {
this.name = name;
}
//唱歌
@Override
public String sing(String name) {
System.out.println(this.name + "正在唱" + name);
return "谢谢";
}
//跳舞
@Override
public void dance() {
System.out.println(this.name + "正在跳舞");
}
/**
* 获取
*
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
*
* @param name
*/
public void setName(String name) {
this.name = name;
}
public String toString() {
return "BigStar{name = " + name + "}";
}
}
创建一个代理类ProxyUtil,利用反射用于增强明星类Star的方法(行为):
/**
* 创建一个代理
*/
public class ProxyUtil {
/**
* 给一个明星的对象,创建一个代理
*
* @param bigStar 被代理的明星对象
* @return 给明星创建的代理
*/
public static Star createProxy(BigStar bigStar) {
Star star = (Star) Proxy.newProxyInstance(
ProxyUtil.class.getClassLoader(),//用于指定类加载器,去加载生成的代理类
new Class[]{Star.class},//指定接口,表明接口内部的方法
new InvocationHandler() {//指定代理对象的增强功能
/**
*
* @param proxy the proxy instance that the method was invoked on
*
* @param method the {@code Method} instance corresponding to
* the interface method invoked on the proxy instance. The declaring
* class of the {@code Method} object will be the interface that
* the method was declared in, which may be a superinterface of the
* proxy interface that the proxy class inherits the method through.
*
* @param args an array of objects containing the values of the
* arguments passed in the method invocation on the proxy instance,
* or {@code null} if interface method takes no arguments.
* Arguments of primitive types are wrapped in instances of the
* appropriate primitive wrapper class, such as
* {@code java.lang.Integer} or {@code java.lang.Boolean}.
*
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if ("sing".equals(method.getName())) {
System.out.println("准备话筒,收钱,开始唱歌");
} else if ("dance".equals(method.getName())) {
System.out.println("准备场地,收钱,开始跳舞");
}
//调用实现类的方法
return method.invoke(bigStar, args);
}
}
);
return star;
}
}
主函数:测试明星的代理人的方法增强效果
public class Test {
public static void main(String[] args) {
//获取代理的方法
BigStar bigStar = new BigStar("鸡哥");
Star proxy = ProxyUtil.createProxy(bigStar);
//调用唱歌的方法
String result = proxy.sing("只因你太美");
System.out.println(result);
/**
* 准备话筒,收钱,开始唱歌
* 鸡哥正在唱只因你太美
* 谢谢
*/
//调用跳舞的方法
proxy.dance();
/**
* 准备场地,收钱,开始跳舞
* 鸡哥正在跳舞
*/
}
}