代理模式
《租房》
今天是7月1日,我毕业了。
于是我开始准备找工作,但是有一个好消息和坏消息。
好消息是:我找到了一份月薪20000的工作
坏消息是:这工作的地方也太特么远了吧!!!💢💢💢💢
于是我决定再公司附近租一个房子,可是问题是,我找不到房东啊?!!
突然看到电线杆上贴的小广告:"低价租房,接收短租,有意者请联系:173xxxxxxxxxx",我毫不犹豫拨通了电话
。。。
半个小时后,中介来了,还带我参观了房子,签了合同
Yes!!我租到了!!
。。。过了一个月,我才发现,这特么是个黑中介😇😇😇
静态代理
租房接口Rent
java
public interface Rent {
void rent();
}
房东类LandHolder😑
java
public class LandHolder implements Rent {
@Override
public void rent() {
System.out.println("房东:租房");
}
}
代理类Mediator🧐
这种代理方式被称为静态代理,因为这个代理只针对一个被代理的对象
比如这个Mediator只能代理LandHolder,因为他不是一个合规中介公司的中介,在合同里面还黑了我800块钱
java
public class Mediator implements Rent {
private Rent rent;
public void setRent(Rent rent) {
this.rent = rent;
}
@Override
public void rent() {
System.out.println("中介:看房");
System.out.println("中介:签合同");
rent.rent();
}
}
我(大冤种🙃🙃)
java
public class Main {
public static void main(String[] args) {
LandHolder landHolder = new LandHolder();
Mediator mediator = new Mediator();
mediator.setRent(landHolder);
mediator.rent();
}
}
//输出结果
//中介:看房
//中介:签合同
//房东:租房
动态代理:JDK的动态代理
三个月过去,我也从这家公司离职了,不过不是我自己辞职,是被辞退的🤐🤐🤐
理由是:我只会静态代理,不符合公司要求(此时我心里一万批🐴在奔腾)
。。。
于是,我去找了一家正规的中介公司(这家公司叫JDK,并且只支持接口代理的动态代理)
不得不说,中介公司就是强大,什么都能代理,租房、租车,甚至是过年租女朋友...
ok,话说回来,他是怎么实现的呢?
同样的
租房接口Rent
java
public interface Rent {
void rent();
}
房东类LandHolder😑
java
public class LandHolder implements Rent {
@Override
public void rent() {
System.out.println("房东:租房");
}
}
我
JDK这家公司就强大在,他给我办理租房服务的时候,会每次都去找到房东对象landHolder ,然后为我去分配处理器invocationHandler ,每次在invocationHandler 中实现办理的逻辑(@Override部分),然后再去创建了proxy代理对象办理业务,真牛逼!!怪不得说什么都能代理呢
java
public static void JDKProxy(){
LandHolder landHolder = new LandHolder();
InvocationHandler invocationHandler = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("中介:看房");
System.out.println("中介:签合同");
method.invoke(landHolder, args);
return null;
}
};
Class<?>[] interfaces = {Rent.class};
Rent proxy = (Rent) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), interfaces, invocationHandler);
proxy.rent();
}
}
动态代理:CGLIB的动态代理
就当我办理好的时候,CGLIB这家代理公司也找上了我,说:JDK能动态代理,我也能动态代理,而且我还是基于类的代理...
我次奥,没听说过啊,于是我线下约了中介,他给我介绍说,我们的代码实现是这样的
房东类LandHolder😑
java
public class LandHolder implements Rent {
@Override
public void rent() {
System.out.println("房东:租房");
}
}
我
我:等等?
中介:怎么了?
我:我靠?!接口呢?
中介:我们是基于类的,不需要那套规则,你就放心好了
我:我看看怎么回事...
。。。。
我:所噶寺内~~,首先找到房东对象landHolder ,然后让landHolder 去造了个儿子模板enhancer ,然后在实现处理逻辑的处理器methodInterceptor ,并添加到enhancer ,再让enhancer.create()一个代理对象,最后代理对象帮我办理业务。
java
public static void CGLIBProxy(){
LandHolder landHolder = new LandHolder();
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(LandHolder.class);
MethodInterceptor methodInterceptor = new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("中介:看房");
System.out.println("中介:签合同");
method.invoke(landHolder, objects);
return null;
}
};
enhancer.setCallback(methodInterceptor);
Rent proxy = (Rent) enhancer.create();
proxy.rent();
}
不对,好像JDK和CGLIB的代理也能坑我钱!!!😣😣😣
总结
代理模式,就是在不改变原有代码的基础上,增强功能
简单来说就是,房子仍然是房东出租的,但是在出租前后代理对象能做一些操作,比如租房前带我看房、租房后给我钥匙之类的。。。
代理分为静态代理和动态代理
-
静态代理
-
缺点:每次需要代理时就需要创建一个代理对象,代码的重用性低,并且增加了开发成本
就比如租房就要一个专门代理,租车也需要一个专门代理,老板没钱发工资啊
-
-
动态代理
-
优点:灵活性高,代码重用性提高
每次的代理的前后逻辑都交给了处理器(invocationHandler /methodInterceptor )去实现,其他的部分都是重复部分,就交给JDK和CGLIB去封装了
-
Spring的IOC与DI
技术:xml文件 + 反射
IOC(inverse of control):控制反转
DI(dependicies injection):依赖注入
依赖注入有
属性注入(使用set方法)
构造注入(使用构造方法)
在以前的代码中,创建并使用对象是如下
java
User user= new User();
//构造方法、设置属性...
System.out.println("user = " + user);
//user = User(name=周珍珍, age=18, userInfo=UserInfo(address=成都理工大专, info=历史悠久的恐龙大专), hobbies=[唱歌, 跳舞], friend=[刘旭, 李淑文, 敖国珍], girlFriend=[刘旭], family={李俊瑶=19, 李虹霖=21}, properties={性格=温和, 身高=150})
但是,引入IOC的概念后,谁创建谁管理,所以就将对象的创建和管理的权力交给了Spring,这就是控制反转
xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 声明一个UserInfo对象-->
<bean class="cn.cnmd.spring.pojo.UserInfo" id="userInfo">
<property name="address" value="成都理工大专"/>
<property name="info" value="历史悠久的恐龙大专"/>
</bean>
<!-- 声明一个User对象-->
<bean class="cn.cnmd.spring.pojo.User" id="user">
<!-- 简单数据类型-->
<property name="name" value="周珍珍"/>
<property name="age" value="18"/>
<!--引用数据类型-->
<property name="userInfo" ref="userInfo"/>
<!--数组类型-->
<property name="hobbies">
<array>
<value>唱歌</value>
<value>跳舞</value>
</array>
</property>
<!--集合类型-->
<property name="friend">
<list>
<value>刘旭</value>
<value>李淑文</value>
<value>敖国珍</value>
</list>
</property>
<property name="girlFriend">
<set>
<value>刘旭</value>
</set>
</property>
<property name="family">
<map>
<entry key="李俊瑶" value="19"/>
<entry key="李虹霖" value="21"/>
</map>
</property>
<!--配置文件类型-->
<property name="properties">
<props>
<prop key="性格">温和</prop>
<prop key="身高">150</prop>
</props>
</property>
</bean>
</beans>
通过applicationContext.xml配置文件的bean的声明,从而让创建对象和管理对象的步骤省略,只需要调用对象
java
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
User user = (User) applicationContext.getBean("user");
System.out.println("user = " + user);
//user = User(name=周珍珍, age=18, userInfo=UserInfo(address=成都理工大专, info=历史悠久的恐龙大专), hobbies=[唱歌, 跳舞], friend=[刘旭, 李淑文, 敖国珍], girlFriend=[刘旭], family={李俊瑶=19, 李虹霖=21}, properties={性格=温和, 身高=150})
是不是很方便呢?