Spring之代理模式和Spring-IOC&DI

代理模式

《租房》

今天是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})

是不是很方便呢?

相关推荐
一元咖啡19 分钟前
SpringCloud Gateway转发请求到同一个服务的不同端口
spring·spring cloud·gateway
儿时可乖了25 分钟前
使用 Java 操作 SQLite 数据库
java·数据库·sqlite
ruleslol26 分钟前
java基础概念37:正则表达式2-爬虫
java
xmh-sxh-131443 分钟前
jdk各个版本介绍
java
天天扭码1 小时前
五天SpringCloud计划——DAY2之单体架构和微服务架构的选择和转换原则
java·spring cloud·微服务·架构
程序猿进阶1 小时前
堆外内存泄露排查经历
java·jvm·后端·面试·性能优化·oom·内存泄露
FIN技术铺1 小时前
Spring Boot框架Starter组件整理
java·spring boot·后端
小曲程序1 小时前
vue3 封装request请求
java·前端·typescript·vue