1.简要概述
- 代理模式就是通过代理对象来控制对真实对象的访问,也就是详细的控制访问某个对象的方法,从而将一些统一的流程代码放到代理类中处理。
- 代理模式中,被代理的对象可以是远程对象、创建开销大的对象、需要安全控制的对象。
- 代理模式是面向切面编程的核心实现思想。
2.模式分类
-
静态代理
在静态代理中,需要定义一个公共接口,代理对象和被代理对象都要实现这个公共接口中的方法。
public interface CommonTeacher{
void teach();
}
public class RealTeacher implements CommonTeacher{
@Override
public void teach(){
System.out.println("开始上课");
}
}
public class ProxyTeacher implements CommonTeacher{
private CommonTeacher realTeacher;
public ProxyTeacher(CommonTeacher realTeacher){
this.realTeacher = realTeacher;
}
@Override
public void teach(){
System.out.println("通知某个教师");
realTeacher.teach();
}
}
public class Client{
public static void main(String[] args) {
ProxyTeacher proxy = new ProxyTeacher(new RealTeacher());
proxy.teach();
}
}
👉优点:在不修改目标对象功能的前提下,能够通过代理对象实现对目标对象的扩展。 👉缺点:由于代理对象和目标对象都要实现统一的接口,一旦接口中增加新的功能方法,那么二者都需要进行更改实现。 -
JDK动态代理
在JDK动态代理中,需要定义一个接口,被代理对象要实现这个接口中的方法。但代理对象不需要实现接口,而是利用JDK中提供的API,动态的在内存中构建代理对象。
public interface CommonTeacher{
void teach();
}
public class RealTeacher implements CommonTeacher{
@Override
public void teach(){
System.out.println("开始上课");
}
}
public class ProxyTeacher implements InvocationHandler{
private CommonTeacher realTeacher;
public ProxyTeacher(CommonTeacher realTeacher){
this.realTeacher = realTeacher;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args){
if(method.getName().equals("teach"))
{
System.out.println("通知某个教师");
method.invoke(realTeacher, args);
}
return null;
}
public Object getProxy(){
return Proxy.newProxyInstance(
ClassLoader.getSystemClassLoader(),
new Class[] {CommonTeacher.class},
realTeacher);
}
}
public class Client{
public static void main(String[] args) {
ProxyTeacher proxy = new ProxyTeacher(new RealTeacher());
CommonTeacher teacher = (CommonTeacher) proxy.getProxy();
teacher.teach();
}
}
👉优点:它是Java原生支持的API,不需要任何其它第三方依赖 👉缺点:它只能基于接口进行实现 -
Cglib代理
在Cglib动态代理中,不需要定义接口,需要定义一个类去实现Cglib包中的MethodInterceptor类,然后在重写的intercept方法中完成被代理对象的调用,最后再通过Enhance工具类生成被代理对象的一个子类,让这个子类充当代理对象。Cglib是一个高性能的代码生成包,底层是通过使用字节码处理框架ASM来转换并生成新的类。
public class RealTeacher{
public void teach(){
System.out.println("开始上课");
}
}
public class ProxyTeacher implements MethodInterceptor{
private RealTeacher realTeacher;
public ProxyTeacher(RealTeacher realTeacher){
this.realTeacher = realTeacher;
}
@Override
public Object intercept(
Object arg0, Method arg1, Object[] arg2, MethodProxy arg3){
System.out.println("通知某个教师");
Object result = arg3.invokeSuper(arg0, arg2);
return result;
}
public Object getProxy(){
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(RealTeacher.class);
enhancer.setCallback(realTeacher);
return (RealTeacher) enhancer.create();
}
}
public class Client{
public static void main(String[] args) {
ProxyTeacher proxy = new ProxyTeacher(new RealTeacher());
ProxyTeacher teacher = (ProxyTeacher) proxy.getProxy();
teacher.teach();
}
}
👉优点:它与代理的目标对象没有使用限制,无需定义和实现任何接口 👉缺点:无法处理被final修饰的方法,因为在创建子类对象的时候无法继承
3.模式结构
👉通常由一个抽象角色( 负责定义真实角色和代理角色的一些公共方法 ),一个代理角色( 负责通过真实角色的业务逻辑方法来实现抽象方法,并附加一些别的操作 ),一个真实角色( 负责实现抽象角色,定义真实角色所要实现的业务逻辑供代理角色调用 ),一个客户类( 负责调用代理对象,完成对真实角色的访问 )共同组成。
4.实现代码
举例 💡 :假设我们现在要租房,而房东希望我们先和中介进行商量已确定价格,然后我们才给房东进行付钱,那么这个处理过程我们就可以使用代理模式处理。
房子(抽象角色)
public interface House {
void talk();
void pay();
}
房子中介(代理角色)
public class HouseProxy implements House{
private Landlord landlord;
public HouseProxy(Landlord landlord) {
this.landlord = landlord;
}
@Override
public void talk() {
System.out.println("找中介谈价格");
}
@Override
public void pay() {
landlord.pay();
}
}
房东(真实角色)
public class Landlord implements House{
@Override
public void talk() {
System.out.println("");
}
@Override
public void pay() {
System.out.println("给房东付钱");
}
}
客户类
public class HouseClient{
public static void main(String[] args) {
House proxy = new HouseProxy(new Landlord());
proxy.talk();
proxy.pay();
}
}
5.优点好处
- 代理对象可以在客户端和目标对象之间起到中介的作用,这样就起到了保护了目标对象的作用。
- 代理对象可以扩展目标对象的功能。
- 代理模式能将客户端与目标对象分离,在一定程度上降低了系统的耦合度。
6.缺点弊端
- 在客户端和目标对象之间增加一个代理对象,会造成请求处理速度变慢。
- 一定程度上增加了系统的复杂度。
7.应用场景
- 当我们想通过代理来控制对远程对象的访问,可以使用远程代理。
- 当我们想利用权限来控制对对象的访问,以此来屏蔽对真实对象的直接访问,可以使用安全代理。
- 当我们需要创建开销很大的对象,先加载一个轻量级的代理对象,以便延迟对真实对象的访问,可以使用虚拟代理。
- 当我们在处理真实对象的时候,希望代理去处理另外一些事情,可以使用智能代理。
8.应用示例
Spring源码中的AOP面向切面编程
|