动态代理:
当我们需要给某个类或者接口中的方法添加一些额外的功能比如日志、事务的时候,
可以通过创建一个代理类来实现这些功能;
该代理类既包含了原有类的完整功能,同时在这些功能的基础上添加了其他的逻辑。
这个代理类不是事先定义好的,而是动态生成的,比较灵活;
基于接口的的动态代理: (使用到java.lang.reflect包下了Proxy类)
代理类至少要实现一个接口
创建代理对象的方法 :Proxy.newProxyInstance(ClassLoader classLoader,Class[] interfaces,InvocationHandler h);
方法参数:
ClassLoader:代理类的类加载器
Class[] interfaces 代理类要实现的接口
InvocationHandler h:代理实例的调用处理程序 实现的接口
用一个演员的例子 创建动态代理对象:
定义一个演员接口
/**
演员接口 (规则:作为演员就必须要有这两个方法)
*/
public interface Act {
//简单演出
void simpleShow(Integer money);
//危险演出
void riskShow(Integer money);
}
代理类Actor 实现Act接口
/**
本类表示演员类
*/
public class Actor implements Act{
//简单演出
public void simpleShow(Integer money) {
System.out.println("简单演出一次"+money+"元");
}
//危险演出
public void riskShow(Integer money) {
System.out.println("危险演出一次"+money+"元");
}
}
Test测试类
public class Test{
public static void main(String[] args) {
//创建演员对象
Actor a = new Actor(); //被代理对象
/*
利用动态代理,增加逻辑判断,简单演出不低于10000块才演出
危险演出不低于20000才演出
在不改变原来的情况下,我们可以使用动态代理,动态的为Actor的方法增强逻辑判断
*/
//使用Proxy创建代理对象: Proxy.newProxyInstance(ClassLoader classLoader,Class[] interfaces,InvocationHandler h);
Act act = (Act)Proxy.newProxyInstance(a.getClass().getClassLoader(),a.getClass().getInterfaces() ,new InvocationHandler(){
/* 重写InvocationHandler类中 invoke方法
*
该方法相当于一个过滤器,调用被代理类的方法,都会先执行invoke方法
方法参数:
Object proxy:代理类的实例
Method method:需要执行的方法
Object[] args:参数
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//获取money的值
Integer money = (Integer)args[0];
//定义一个null对象 ,接收代理类方法放回的结果,作为invoke方法的返回值
Object obj = null;
//判断money的值:简单演出不低于10000块才演出,危险演出不低于20000才演出
//如果是简单方法
if("simpleShow".equals(method.getName())) {
//money 不低于10000 才演出
if(money>=10000) {
/*
* method.invoke(obj,args )
* obj - 从中调用底层方法的对象
* args - 用于方法调用的参数
*/
obj = method.invoke(a,money);//obj 接收方法的返回值,即使是void也有返回值对象
}
}
//如果是危险方法
if("riskShow".equals(method.getName())) {
//money 不低于20000 才演出
if(money>=20000) {
obj = method.invoke(a,money); //方法执行开始危险表演
}
}
return obj;//invoke 方法会返回值,而返回值void,也是一个Void对象
}
});
//使用动态代理类,调用简单演出
act.simpleShow(1000);
//使用动态代理类,调用危险演出
act.riskShow(30000);
}
}
输出:
危险演出一次30000元
简单演出低于10000块钱,演员拒绝演出