目录
一,代理模式:
目标对象不可访问,通过代理对象增强功能访问,实现访问目标对象。如:租房子,需要通过房屋中介来实现租房。目标对象:房东,代理对象:中介,客户端对象:租客。
1,代理模式的作用:
1)控制目标对象的访问
2)增强功能
2,代理的分类:
1),静态代理
2)。动态代理
a,JDK动态代理
b,CGLib动态代理
二,静态代理:
代理模式的一种,
特点:
1)目标对象和代理对象实现同一个业务接口
2),目标对象必须实现接口
3),代理对象在运行前就已经存在
4),能够灵活切换目标对象,却无法进行功能的灵活处理(使用动态代理处理)
4,静态代理执行流程:
5,面向接口编程:
1,内部成员属性定义为接口类型,2,方法的返回值定义为接口,3,方法的参数定义为接口
三,动态代理
动态代理:
灵活的进行功能切换的要求
静态代理:能够灵活切换目标对象,却无法进行功能的灵活处理(所以要使用使用动态代理处理)
代理对象在程序运行时动态在内存构建,可以灵活的进行业务切换。
一),JDK动态代理
a,目标对象必须实现业务接口
b,JDK代理对象不需要实现业务接口
c,JDK动态代理的对象,在程序运行前不存在,在程序运行时,动态的在内存构建
d,JDK灵活的进行任务切换。
e,本类中的自己的方法,不可以被代理
1,JDK动态代理的常用工具类
1),Proxy(代理)类
java.lang.reflect.Proxy包下的类
产生JDK动态代理的方法:
Proxy.newProxyInstance(.....)
newProxyInstance(...)的参数解读:
ClassLoader://类加载器
Class<?>[] :目标对象实现的全部接口
InvocationHandler:代理的功能和目标对象业务的实现都在该接口下的实现类中
2),Method类:
反射用的类,用来进行对目标对象的方法的反射调用。
method.invoke();//调用方法
3),InvocationHandler(调用代理)接口
实现代理的功能和调用目标对象重写接口的方法,使用匿名内部类来实现
2,代码实现
业务接口:
public interface Service {
void buy();
String getName(String name);
}
目标对象1:
public class Women implements Service {
@Override
public void buy() {
System.out.println("买小裙子。。。。");
}
@Override
public String getName(String name) {
System.out.println(name);
return name;
}
}
目标对象2:
public class Man implements Service {
@Override
public void buy() {
System.out.println("买包华子。。。");
}
@Override
public String getName(String name) {
return name;
}
}
代理工厂:程序运行时动态的创建代理对象
public class ProxyFactory {
Service service;
public ProxyFactory(Service service){
this.service = service;
}
//获取JDK动态代理对象
public Object getAgent(){
return Proxy.newProxyInstance(
service.getClass().getClassLoader(),//获得目标对象的类加载器
service.getClass().getInterfaces(),//获得目标对象的实现的所有接口
new InvocationHandler() {//动态代理对象的功能
@Override
public Object invoke(
Object proxy,//创建动态代理对象
Method method,//代理对象需要调用的方法
Object[] args//目标方法的参数
) throws Throwable {
//代理功能
System.out.println("去商场");
//目标对象功能,args是方法运行需要的参数
Object invoke = method.invoke(service, args);
//代理功能
System.out.println("买到了");
return invoke;//返回目标方法的返回值
}
}
);
}
}
测试:
public static void main(String[] args) {
Service service = new Women();
//这里不能传入实现类的匿名对象,需要先将实现类的类型提升为接口,在将替身后的对象传入,否则会出现类型转换异常
ProxyFactory factory = new ProxyFactory(service);
Service agent = (Service) factory.getAgent();
//这里得到的对象类型是:class com.sun.proxy.$Proxy0
System.out.println(agent.getClass());
//因为他是Proxy类型的对象,所以除了这个接口的方法,实现类自己的方法是无法通过该对象来调用的
agent.buy();
agent.getName("张三");
}
二),CGLib动态代理(又称子类)
通过动态的在内存中构建子类对象,重写父类的方法,进行代理功能的增强
即在实现类没有实现接口时,通过CGLib子类代理来进行功能加强。(有点像继承)