zoukankan      html  css  js  c++  java
  • [Spring]IOC控制反转和DI依赖注入

    从之前算起到现在接触Spring也已经有几天了,进度也不是很快,就只弄懂了控制反转和依赖注入那么一点东西.然后敲了两个demo

    主要是因为之前没有学过,然后网上资源很多但是都不是面向我们初学者的,大多都是直接上一堆配置,一堆代码纯粹告诉我如何用,而我敲完之后却不知道原理,在这里我算是淌过几次坑了

    我找过W3School,上面的基础挺详细,各种概念给你讲清楚,但是它的教程有点老,Spring教程好像最后更新是16年,而且,有些地方对小白不是很友好,比如他没有提供需要导入的jar包,这一点上How2j做的不错

    但是个人感觉How2j上的是简洁版的Spring,站长省略掉了其中的一些东西,之后我干脆找了外面java培训的视频看,感觉挺不错,某宝上有教程卖,十多块就可以买到(这里真的不是打广告)

    Spring框架的介绍就不多说了,

    Spring的下载地址:http://repo.spring.io/release/org/springframework/spring/

    Spring的依赖包下载:http://s3.amazonaws.com/dist.springframework.org/release/SPR/spring-framework-3.0.2.RELEASE-dependencies.zip(自从有些版本以后Spring就没有提供这个了)

     

    IOC:

    IOC称为控制反转,控制反转的意思就是将创建对象的权利转交,我们以前创建对象的方式是new Object();而这样容易造成对象之间高耦合,那么什么是耦合呢,我的理解是他们之间的关系过于紧密

    这样如果我们需要加入新的功能的时候就要改动源代码,不仅不利于测试而且也会让程序不便扩展,那么在Spring采用什么方式生成对象,这里就要涉及到DI,即依赖注入了

    那么问题来了

    依赖是谁依赖谁,当然是程序依赖于IOC容器(ApplicationContext或者BeanFactory)

    为什么要依赖,因为程序不再通过new Object()生成对象,必须通过容器所提供的资源来创建对象

    注入的是什么,是容器中的资源(包括对象,常量等)

    那么IOC这种方式是怎样来生成对象的呢

     首先,在程序中,有一个applicationContext.xml的文件,当然其他名字也没问题,我们得到对象的方式就是通过解析这个XMl文件,然后再反射来得到对象的

    首先看一个applicationContext.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-3.0.xsd">
    
        <bean id="UserServiceImpl"
              class="com.example.demo1.Implements.UserServiceImpl"
              init-method="init"
              destroy-method="destroy"
              scope="prototype">
            <constructor-arg name="service" ref="service"></constructor-arg>
        </bean>
        <bean id="service" class="com.example.demo1.Implements.UserServiceImpl"></bean>
    </beans>

    这里的bean标签通俗的来说,如果把ApplicationContext比作一个工厂的话,bean就是这个工厂的产品,然后工厂根据他里面的id和class(即要生成的对象对应的实现类)来生成对象

    解析xml文件,得到他的class的名字,通过反射找到该类,再生成对象,通过这个过程,我们把对象的控制权完全交给了spring,而不是之前的new Object()

    通过解析XML得到对象的代码:

    ApplicationContext instance = new ClassPathXmlApplicationContext("applicationContext.xml");
            UserServiceImpl serviceImpl = (UserServiceImpl) instance.getBean("UserServiceImpl");
            serviceImpl.save();//save为对象的一个方法

    ClassPathXmlApplicationContext表示是在工程路径下面搜索该XML文件,如果要在电脑磁盘中寻找.需要用FileSystemApplicationContext

    bean标签的相关属性

    拿上面的XML为例子

    id表示对象的唯一标识,也就是说这个不同的bean的id是不同的,他的命名规范和java变量的命名规范是一样的,不能出现特殊字符,比如?><这些,同时也不能纯数字

    name的话,可以用特殊字符和纯数字但是不能出现空格,但是就不同的bean可以用同一个,就像人的身份证和名字一样,身份证只有一个,但名字可以是相同的,但是这仅建立在指定ID的的情况下

    如果没有指定ID,name会被当做id,同样还是会报错

    对比这两张截图

    init-method属性是bean的初始方法,在创建好bean后调用该方法。

    destory-method属性是bean的销毁方法,在销毁bean之前调用该方法,一般在该方法中释放资源

    scope属性表示bean的作用范围,scope有4个值:

    singleton:表示整个IOC容器共享一个Bean,也就是说每次说每次通过getBean获取的bean都是同一个。

    prototype:每次对该bean请求(将其注入到另一个bean中,或者以程序的方式调用容器的getBean()方法)时都会创建一个新的bean实例。

    request:每次HTTP请求将会生成各自的bean实例

    session:每次会话请求对应一个bean实例

    后面两个一般用于web项目中

    autowire表示bean的自动装配,autowire的值有:

    no : 默认值,不进行自动装配

    byName : 根据属性名自动装配。此选项将检查容器并根据名字查找与属性完全一致的bean,并将其与属性自动装配

    byType : 如果容器中存在一个与指定属性类型相同的bean,那么将与该属性自动装配;如果存在多个该类型bean,那么抛出异常,并指出不能使用byType方式进行自动装配;如果没有找到相匹配的bean,则什么事都不发生,也可以通过设置dependency-check="objects" 让Spring抛出异常。

    constructor:与byType方式类似,不同之处在于它应用于构造器参数。如果容器中没有找到与构造器参数类型一致的bean, 那么抛出异常

    autodetect : 通过bean类的内省机制(introspection)来决定是使用constructor还是byType方式进行自动装配。如果发现默认的构造器,那么将使用byType方式,否则采用 constructor。

    default:由上级标签的default-autowire属性确定。

    注入

    1.setter的方法

    2.构造的方法

    测试类

    package com.example.demo1.Implements;
    
    import com.example.demo1.Interface.UserService;
    
    public class UserServiceImpl implements UserService {
        private UserServiceImpl service;
        public void init(){
            System.out.println("初始化");
        }
        public void destroy(){
            System.out.println("销毁");
        }
        public UserServiceImpl(UserServiceImpl service){
            this.service = service;
        }
    
        public void setService(UserServiceImpl service) {
            this.service = service;
        }
    
        public UserServiceImpl(){
    
        }
        @Override
        public void save() {
            System.out.println("保存信息"+this.hashCode());
        }
    }
    <property name="service" ref="test"></property>对应setService()
    <constructor-arg name="service" ref="service"></constructor-arg>对应构造函数

    P名称空间注入
    先在xml文件里添加一行
    xmlns:p="http://www.springframework.org/schema/p"
    对于非对象属性,直接采用P:属性名.即可以注入,例如我一个类中有name和password属性
    那么在xml文件里便可以通过如下方式注入
    <bean id="Client"
              class="com.example.demo1.Implements.UserClientImpl"
              p:name="lidong" p:password="123">
        </bean>

    SpEL表达式注入

     SpEL全称SpringExpressionLanguage,SpEL 使用 #{...} 作为定界符 , 所有在大括号中的字符都将被认为是 SpEL , SpEL 为 bean 的属性进行动态赋值提供了便利。

    通过 SpEL 可以实现:

    • 通过 bean 的 id 对 bean 进行引用。
    • 调用方式以及引用对象中的属性。
    • 计算表达式的值
    • 正则表达式的匹配。

    看代码吧还是

    <bean id="UserClient" class="com.example.demo1.Implements.UserClientImpl">
            <property name="name" value="#{555*123}"></property>
            <property name="password" value="#{123}"></property>
        </bean>

    这里我在name标签处使用了一个乘法

    然后打印出,可以看出这里面进行了运算

  • 相关阅读:
    @PathVariable和@RequestParam的区别,@SessionAttributes
    forward和redirect的区别
    JSP页面的静态包含和动态包含
    ConcurrentHashMap源码解析
    Jdk1.6 JUC源码解析(1)-atomic-AtomicXXX
    最小生成树
    tomcat启动项目内存溢出问题
    强引用,弱引用,4种Java引用浅解(涉及jvm垃圾回收)
    CXF 在WAS上报Unmarshalling Error的问题
    CXF处理Date类型的俩种方式
  • 原文地址:https://www.cnblogs.com/Yintianhao/p/9710930.html
Copyright © 2011-2022 走看看