1.什么是代理模式
为某个对象提供一个代理对象,通过这个代理对象,可以控制对原对象的访问。
通俗的解释:我们电脑桌面上的一个个快接方式,当我们点击这个快捷方式的时候,我们就间接地访问到了这个程序。
2.静态代理
何为静态?即在程序运行之前,代理类已经由程序员写好并生成.class文件了
下面是一个最最简单的例子,目的:使用鸡的代理对象,来帮我们创建鸡这个动物
2.1静态代理的简单代码实现
首先,创建一个接口,他代表所有的动物,规定了动物的所有行为
public interface Animal {
void cry();
}
下面创建一个被代理对象的实体,这里以鸡为例
public class Chick implements Animal{
private String name;
public Chick(String name) {
this.name = name;
birth(name);
}
private void birth(String name) {
System.out.println("名字是"+name+"的鸡出生了");
}
@Override
public void cry() {
System.out.println("我是一只叫"+name+"的鸡");
}
}
下面是鸡这个动物的代理类,同样也要实现Animal接口
public class ProxyChick implements Animal{
private String name;
private Chick chick;
public ProxyChick(String name) {
this.name = name;
}
@Override
public void cry() {
if (chick==null){
chick = new Chick(name);
}
chick.cry();
}
}
测试使用鸡的代理类来获取鸡
public class ProxyTest {
public static void main(String[] args){
ProxyChick chick = new ProxyChick("蔡徐坤");
chick.cry();
System.out.println("================");
chick.cry();
}
}
2.2java中应用
spring的Aop
还记得面向面向切面编程吗?他又是如何实现对方法进行加强的呢?其实只要在代理对象调用被代理对象方法的前后加上要增强的内容即可。
我们可以在cry方法前后任意的位置去写我们增强的逻辑,下面就用两个print输出来模拟增强方法。
public class ProxyChick implements Animal{
private String name;
private Chick chick;
public ProxyChick(String name) {
this.name = name;
}
@Override
public void cry() {
if (chick==null){
chick = new Chick(name);
}
//在方法之前增强
System.out.println("一个真正的鳗");
chick.cry();
//在方法之后增强
System.out.println("要学会唱跳rap打篮球");
}
}
2.3静态代理的优缺点
- 优点:
- 使用代理模式,给程序带来了高扩展性
- 缺点:
- 为了实现代理模式,带来了额外的工作
- 由于使用被代理对象之前需要经过代理对象,会增加时间开销
- 使用静态代理,需要程序员编写大量的代理对象加大工作量
3.动态代理
核心:不用事先为想代理的类创建代理对象
代码实现重点:java.lang.reflect包下提供的Proxy类和InvocationHandler接口
下面是简单的动态代理实现流程
3.1动态代理的简单代码实现
前几步和静态代理类似,首先,先创建一个接口,定义行为
public interface Animal {
void cry();
}
创建接口的实现类,也就是被代理的类
public class Chick implements Animal{
private String name;
public Chick(String name) {
this.name = name;
birth(name);
}
private void birth(String name) {
System.out.println("名字是"+name+"的鸡出生了");
}
@Override
public void cry() {
System.out.println("我是一只叫"+name+"的鸡");
}
}
接下来,就是动态代理的具体实现,创建AnimalInvocationHandler类,他实现了InvocationHandler接口
动态代理流程解析:
1.AnimalInvocationHandler持有一个被代理对象
2.通过代理对象执行的方法,都会被替换成AnimalInvocationHandler中的invoke方法
3.代理对象会在invoke方法中,去执行被代理对象的方法,和invoke方法中其他代码语句
上述的三个步骤,其实就是Spring Aop的主要原理
public class AnimalInvocationHandler<T> implements InvocationHandler {
//持有一个被代理的对象
private T target;
public AnimalInvocationHandler(T target) {
this.target = target;
}
/**
* 其中的三个参数
* proxy:表示这个动态代理的对象
* method:正在执行的方法
* args:调用方法时传入的参数
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("正在代理执行"+proxy.getClass().getName()+"类的"+method.getName()+"方法");
Object invoke = method.invoke(target, args);
System.out.println("代理执行结束~");
return invoke;
}
}
测试
public class DynamicProxyTest {
public static void main(String[] args) {
//创建出被代理的对象
Animal chick = new Chick("蔡徐坤");
System.out.println("======================");
//创建InvocationHandler,他和被代理对象是相关联的
InvocationHandler chickHandler = new AnimalInvocationHandler<Animal>(chick);
//得到代理对象,代理对象执行的每一个方法都会被刚刚InvocationHandler中的invoke方法代替
Animal chickProxy = (Animal) Proxy.newProxyInstance(Animal.class.getClassLoader(),new Class<?>[]{Animal.class},chickHandler);
chickProxy.cry();
}
}
上面的代码解析:首先,chick对象是需要被代理的对象,我们把chick传给了chickHandler,并且,创建代理对象chickProxy时,chickHandler也是作为一个参数传入,最后,代理对象chickProxy中的方法在执行的时候,都被替换成了chickHandler中的invoke方法。
3.2动态代理的特点
- 与静态代理不同,在上面的代码实现中,我们没有看到具体的代理类,动态代理中的被代理对象和代理对象,是通过InvocationHandler来完成代理的,所以就无须对每一个类都写一个代理类,只需要同一在invoke方法中修改即可。