这是我参与更文挑战的第25天,活动详情查看:更文挑战
一、什么是代理模式
先来看看百度的解释
代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。 ——百度百科
个人感觉这个将的太抽象了,不过这里有个概念-“中介”,这个词就很能体现代理模式的精髓,一切代理模式其实都是一个中介,能够让使用者去使用不方便直接使用的对象,而不需要考虑其中复杂的过程。
二、使用代理模式的优缺点
1.优点
- 让代码的职责更加清晰,经过代理之后,在使用方法时就不需要考虑业务逻辑之外的东西
- 具有高扩展性,能够很好的与其他方法进行组合
- 代理对象可以在客户端和目标对象之间起到中介的作用,这样起到了中介的作用和保护了目标对象的作用
2.缺点
- 增加了系统复杂度,这也是不可避免的,代理模式在不影响使用的情况下,增加了额外的功能,必然会增加复杂度
- 由于在客户端和真实对象之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢(个人觉得,实例之间的相互调用应该是一个很迅速的过程,有没有代理的效率应该是差不多的)
3.原则
“+”代表遵守,“-”代表不遵守或者不相关
原则 | 开放封闭 | 单一职责 | 迪米特 | 里氏替换 | 依赖倒置 | 接口隔离 | 合成复用 |
---|---|---|---|---|---|---|---|
- | + | - | - | + | + | - | |
三、代理模式的分类
我这里不是按照实现方法来进行分类的,而是按照代理模式的本质来分类的。
1.增强型代理
- 特点
核心功能不变(不能修改原来的功能) 业务无关性(不修改核心的业务逻辑,降低系统的复杂性) 使用习惯不变 附加新功能(只是让需要代理的功能附加不影响原来的功能的功能,相当于加个buff) 普适性(增强的功能能够加到其他方法中)
总的来说,增强型代理只是对一个方法进行一些无关业务的操作,安全校验,上锁,记录等一些无关业务的操作。
- 常见的例子
增强代理的实现可以有静态代理,也可以有动态代理 常见的例子有:
- spring的aop,声明型事物
- 监控操作(当用户操作后,做一个记录)
2.链接型代理
- 特点
跟增强型代理一些相似的特点 核心功能不变 业务无关性 使用更加方便
总的来说,链接型代理就是简化我们对方法的调用,也是不改变业务,一般来说,不会做一些增强型的操作。
- 常见的例子
链接型代理的实现同样也是可以静态,也可以动态。 常见的例子有:
- MyBtis的mapper代理
- springCloud中的ribbon,zuul等
四、代理模式的实现
1.静态代理
静态代理就是采用手动写代码的方式来实现,可以在不修改目标对象功能的前提下,实现功能扩展,扩展多样化,但是需要编写很多方法的扩展,管理成本增大 首先需要创建一个接口,接口中定义被代理类和代理类都要实现的方法,然后创建被代理类和代理类
/**
* @author xxj
* 静态代理测试
*/
public class StaticProxy {
public static void main(String[] args) {
Company company=new Company("房地产公司","靠海别墅");
CompanyProxy companyProxy=new CompanyProxy(company,"小张");
companyProxy.sale();
}
/**
* 接口
* 卖东西的接口
*/
public interface Salor{
public void sale();
}
/**
* 被代理类
* 需要代理的公司
*/
public static class Company implements Salor{
String name;
String product;
public Company(String name,String product){
this.name=name;
this.product=product;
}
@Override
public void sale() {
System.out.println(name+"卖出"+product);
}
}
/**
* 代理类
* 中介
*/
public static class CompanyProxy implements Salor{
private Company company;
private String worker;
/**
* @param company 需要代理的公司
*/
public CompanyProxy(Company company,String worker){
this.company=company;
this.worker=worker;
}
@Override
public void sale() {
System.out.println(worker+"推销--联系客户---");
System.out.println("联系"+company.name+"进行交易--");
company.sale();
System.out.println(worker+"拿提成--");
}
}
}
个人感觉这更像链接型代理,因为CompanyProxy的sale方法中是有做相关操作的(如果把打印到控制台理解为一个操作),而增强型代理则是打印一下状态信息或者是监控,而不会去执行company.sale()
2.动态代理
动态代理生成的代理类都是通过动态拼接字节码产生的,实际上代理类并不存在,而静态代理中代理类则是真是存在的
JDK动态代理
JDK动态代理就不需要手动地去扩展方法的功能了,而是由一个实现了InvocationHandler接口的类来统一管理,不用写每个方法的扩展,使代理类的管理成本降低,但是会是代理类的创建变得麻烦,这就可以套上一个工厂模式来创建代理类了
首先依然是要创建一个接口,被代理类需要实现这个接口,然后在创建一个中介类实现InvocationHandler接口,然后调用Proxy提供的静态方法newProxyInstance来创建代理类(注意需要用接口接收)
/**
* @author xxj
* JDK动态代理
*/
public class DynamicProxy {
public static void main(String[] args) {
Company company=new Company("房产公司","傍山别墅");
//中介公司
CompanyHandler companyHandler=new CompanyHandler(company,"啥都能卖公司");
//类加载器,可以强行理解为销售组长,要由他来叫人干活
ClassLoader classLoader=company.getClass().getClassLoader();
//叫张三来替啥都能卖公司干活
Salor zhangsan= (Salor) Proxy.newProxyInstance(classLoader,
company.getClass().getInterfaces(),companyHandler);
zhangsan.sale();
}
/**
* handle类
* 相当于中介公司
*/
public static class CompanyHandler implements InvocationHandler{
private Company company;
private String agentCompany;
public CompanyHandler(Company company,String agentCompany){
this.company=company;
this.agentCompany=agentCompany;
}
/**
* @param proxy 貌似不能使用
* @param method 调用invoke的method信息
* @param args method的参数信息
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(agentCompany+"推销--联系客户---");
System.out.println("联系"+company.name+"进行交易--");
//执行company的方法
method.invoke(company,args);
System.out.println(agentCompany+"拿提成--");
return null;
}
}
/**
* 被代理类
* 需要代理的公司
*/
public static class Company implements Salor {
String name;
String product;
public Company(String name,String product){
this.name=name;
this.product=product;
}
@Override
public void sale() {
System.out.println(name+"卖出"+product);
}
}
/**
* 接口
* 卖东西的接口
*/
public interface Salor{
public void sale();
}
}
Cglib动态代理
Cglib动态代理使用起来就比JDK动态代理方便多了,只需要写一个ProxyFactory类就可以给其他类做代理了,而且不需要再写接口了,但是它生成代理类的过程比较复杂,还需要依赖第三方jar包 首先,需要导入依赖,然后只需要写一个代理工厂类,需要实现MethodInterceptor接口,还要在内部提供构建代理类的方法,直接把被代理类放入代理工厂类就可以生成代理类了
maven
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
/**
* @author xxj
* Cglib动态代理
*/
public class CglibDynamicProxy {
public static void main(String[] args) {
Company company=new Company("房产公司","私人庄园");
Company proxy= (Company) new ProxyFactory(company,"一定能卖出公司").getProxyInstance();
proxy.sale();
}
public static class ProxyFactory implements MethodInterceptor {
private Company company;
private String agentCompany;
public ProxyFactory(){}
public ProxyFactory(Company company, String agentCompany){
this.company=company;
this.agentCompany=agentCompany;
}
//给目标对象创建一个代理对象
public Object getProxyInstance(){
//1.工具类
Enhancer en = new Enhancer();
//2.设置父类
en.setSuperclass(company.getClass());
//3.设置回调函数
en.setCallback(this);
//4.创建子类(代理对象)
return en.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println(agentCompany+"推销--联系客户---");
System.out.println("联系"+company.name+"进行交易--");
//执行company的方法
method.invoke(company,objects);
System.out.println(agentCompany+"拿提成--");
return null;
}
}
/**
* 被代理类
* 需要代理的公司
*/
public static class Company {
String name;
String product;
public Company(){}
public Company(String name,String product){
this.name=name;
this.product=product;
}
public void sale() {
System.out.println(name+"卖出"+product);
}
}
}
五、总结
无论那种代理模式都需要满足不改变核心功能,不改变业务逻辑这两个特点,一旦违背了,就会极大的增加系统的复杂度。
这里分别举两个生活中的例子来作为本章节的结束吧。 增强型代理,就像是微波炉(代理对象),当我们需要加热食物(被代理对象)时,就将食物放入微波炉中,然后我们就会得到一个加热了的食物(附加新功能)。这个过程没有改变食物的本质(不改变核心功能),我们依然能吃(说加热太烫吃不了的,你就杠吧)(使用习惯不变)一切食物都可以加热(普适性)你想加热别的东西也可以。 链接型代理,这个可以举的例子太多了,像宅急送,我们只需要手机下单就可以购买汉堡(使用更加方便)我们手机下单最终做的事情就是买汉堡(不改变核心功能)
——————————————————————————————
这里是程序员徐小白,不知道这样的文章风格您是否喜欢,不要吝啬您免费的赞,您的点赞、收藏以及评论都是我下班后坚持更文的动力。
未经允许,不得转载!