描述
北堂先生要去租房,那么肯定会去找中介(二房东),中介就是房东的代理者,我原来访问不了房东,有了中介可以访问了。所以代理模式的定义是给某对象提供一个代理对象,通过代理对象可以访问该对象的功能。主要解决通过代理去访问[不能直接访问的对象]
这样的优点是:
1、职责清晰。
2、高扩展性。
3、智能化。
缺点是:
1、由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢。
2、实现代理模式需要额外的工作,有些代理模式的实现非常复杂。
代理实现方式:
基于接口的动态代理
提供者:JDK官方的Proxy类。
要求:被代理类最少实现一个接口。
基于子类的动态代理
提供者:第三方的CGLib,如果报asmxxxx异常,需要导入asm.jar。
要求:被代理类不能用final修饰的类(最终类)。
JDK动态代理
JDK动态代理要点:
1、被代理的类必须实现一个接口
2、创建代理对象的时候,用JDK代理需要实现InvocationHandler
3、代理过程在invoke中实现
以北堂先生租房为例,通过中介直接租房,中介充当代理角色,房东充当被代理角色。
创建房东接口对象(遵循开闭原则):
public interface LandlordService {
void renting(String name);
}
创建房东对象
public class Landlord implements LandlordService {
@Override
public void renting(String name) {
System.out.println("嘿!" +name+" 该交房租了!");
}
}
创建代理处理对象(小明):
每一个动态代理类的调用处理程序都必须实现InvocationHandler接口,并且每个代理类的实例都关联到了实现该接口的动态代理类调用处理程序中,当我们通过动态代理对象调用一个方法时候,这个方法的调用就会被转发到实现InvocationHandler接口类的invoke方法来调用
- proxy:代理类代理的真实代理对象com.sun.proxy.$Proxy0
- method:我们所要调用某个对象真实的方法的Method对象
- args:指代代理对象方法传递的参数
public class XiaoMProxy implements InvocationHandler {
private Object instance;
public XiaoMProxy(Object instance) {
this.instance = instance;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
args[0] = "小明带领"+args[0];
Object result = method.invoke(instance, args);
return result;
}
}
.Proxy类就是用来创建一个代理对象的类,它提供了很多方法,但是最常用的是newProxyInstance方法。
public static void main(String[] args) {
LandlordService landlord = new Landlord();
// 代理
XiaoMProxy xiaoMProxy = new XiaoMProxy(landlord);
// 可以调用房东的方法
/**
* loader:一个classloader对象,定义了由哪个classloader对象对生成的代理类进行加载
* interfaces:一个interface对象数组,表示我们将要给我们的代理对象提供一组什么样的接口,如果我们提供了这样一个接口对象数组,那么也就是声明了代理类实现了这些接口,代理类就可以调用接口中声明的所有方法。
* h:一个InvocationHandler对象,表示的是当动态代理对象调用方法的时候会关联到哪一个InvocationHandler对象上,并最终由其调用。
*/
LandlordService proxy = (LandlordService) Proxy.newProxyInstance(LandlordService.class.getClassLoader(),new Class[]{LandlordService.class},xiaoMProxy);
proxy.renting("北堂");
}
运行结果如下:嘿!小明带领北堂 该交房租了!
CGLib动态代理
CGLib动态代理要点:
1、代理过程可以实现MethodInterceptor(Callback)接口中的invoke来实现
2、通过Enhancer来创建代理对象
上面小明换成小陈继续
public class XiaoCProxy implements MethodInterceptor {
/**
*
* o:cglib生成的代理对象
* method:被代理对象方法
* objects:方法入参
* methodProxy: 代理方法
* @return
* @throws Throwable
*/
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
objects[0] = "小陈带领" + objects[0];
return method.invoke(objects[0]);
}
}
public static void main(String[] args) {
LandlordService landlordService = new Landlord();
XiaoCProxy xiaoCProxy = new XiaoCProxy(landlordService);
LandlordService proxy = (LandlordService) Enhancer.create(LandlordService.class,xiaoCProxy);
proxy.renting("北堂");
}
结果:嘿!小陈带领北堂 该交房租了!
Spring AOP-动态代理
基于SpringAOP可以实现非常强大的功能,例如声明式事务、基于AOP的日志管理、基于AOP的权限管理等功能,利
用AOP可以将重复的代码抽取,重复利用,节省开发时间,提升开发效率。Spring的AOP其实底层就是基于动态代理
而来,并且支持JDK动态代理和CGLib动态代理,动态代理的集中体现在 DefaultAopProxyFactory 类中。
如果我们在spring的配置文件中不配置 <aop:config proxy-target-class=“true”> ,此时默认使用的将是JDK动态
代理,如果配置了,则会使用CGLib动态代理。