[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标签处使用了一个乘法

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

原文地址:https://www.cnblogs.com/Yintianhao/p/9710930.html