小白新手web开发简单总结(六)-Spring的IoC容器

目录

一 前言

二 什么是IoC容器

三 实例

1.通过XML配置规则

2.通过注解

3.Spring中的其他几种注解

四 JavaBean生命周期的监听

五 总结


一 前言

接上篇小白新手web开发简单总结(四)-web应用开发中的MVC总结下IoC容器的相关内容。

IoC容器是Spring框架的一个核心功能。通过该容器来管理所有的JavaBean组件,提供组件的生命周期管理、配置和组装、AOP支持、以及建立在AOP基础上的声明事务服务等。

二 什么是IoC容器

IoC(Inversion of Control 控制反转)容器

通常Java组件通过new一个实例的方式实现组件之间的引用,并且组件中的两个实例都含有共享组件的时候,也不能共享该组件。如果系统中有大量的组件的时候,不仅要维护组件的生命周期,还要维护组件之间的依赖关系,大大增加了系统的复杂度,而且组件之间会相互耦合,这些控制流程完全有开发者自行控制。

而IoC容器就是将控制权进行反转,将控制权交给了IoC容器,由IoC容器负责组件的创建和配置,负责组件的生命周期管理,而开发者只需要定义装配规则,这样就将组件的创建配置和组件的使用进行分离。并且如果在一个组件的多个实例中含有共享组件的时候,是可以相互共享的,不需要多次注入。

在Spring的IoC容器中,所有的组件都被成为JavaBean组件,每个组件即一个Bean。

通常有两种方式来定义组件的配置规则:

  • (1)XML
  • (2)注解

三 实例

通过一个简单的实例来看下这个JavaBean组件是怎么定义配置规则。

1.通过XML配置规则

  • 1.在项目pom.xml中引入spring-context依赖
        <dependency>            <groupId>org.springframework</groupId>            <artifactId>spring-context</artifactId>            <version>${spring.version}</version>        </dependency>
  • 2.定义项目中需要使用的JavaBean

(1)定义一个RegisterService:通过输入的手机号码和密码,来注册该用户,并将注册成功之后给用户发送注册成功的短信。

public class RegisterService {    private MessageService messageService;    public void setMessageService(MessageService service) {        this.messageService = service;    }    public User register(String phone, String password) {        User user = new User();        user.phone = phone;        user.password = password;        //随机生成一个用户名        user.name = "小刘";        //需要将该信息写入数据库        SqlDataBase sql = new SqlDataBase();        sql.insert(user);        //注册成功之后,给用户发送短息        if (messageService == null) {            System.err.println("还没有初始化MessageService");            return user;        }        messageService.sendRegisterSuccessMessage(phone);        return user;    }}

(2)定义MessageService: 向用户的手机发送短信(逻辑省略)

public class MessageService {    /**     * 发送短信     *     * @param phone     */    public void sendRegisterSuccessMessage(String phone) {        String message = "您已经成功注册该网站账户";        System.out.println(String.format("已经成功的向%s发送注册短信:%s", phone, message));    }}
  • 3.定义配置JavaBean的规则

(1)在resouce目录下添加application-context.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        https://www.springframework.org/schema/beans/spring-beans.xsd">    <bean id="registerService" class="com.wj.spring.RegisterService">        <property name="messageService" ref="messageService"/>    </bean>    <bean id="messageService" class="com.wj.spring.MessageService">    </bean></beans>

其中id为该bean的唯一识别 ,通过 <property name="messageService" ref="messageService"/>的方式在RegisterService中增加了MessageService的引用,其实上面的XML配置的内容就等价于下面的java代码:

    MessageService messageService = new MessageService();    RegisterService registerService = new RegisterService();    registerService.setMessageService(messageService);
  • 4.通过读取XML文件,获取到ApplicationContext,也就是IoC容器
public class RegisterApplication {    public static void main(String[] args) {        ApplicationContext context = new ClassPathXmlApplicationContext("config/application-context.xml");        RegisterService service = context.getBean(RegisterService.class);        //RegisterService service = (RegisterService)context.getBean("registerService");        User user = service.register("12345678901", "123456");        System.out.println("注册之后的用户名为:"   user.name);          }}

当 ClassPathXmlApplicationContext要传入的是这个application-context.xml的相对路径。这样就可以context.getBean()的方式获取到定义的JavaBean。运行项目如下:

相关的代码已经上传到github:https://github.com/wenjing-bonnie/build-spring.git:对应的com/wj/spring下的相关代码。

2.通过注解

使用XML文件的方式,可以把所有的JavaBean的都一一列举出来,并且通过配置注入能直观的了解到每个JavaBean的依赖关系,但是缺点也就显现出来,这种写法非常繁琐,每增加一个组件,就必须在XML将该组件添加进去。所以就有了注解这种方式,可以让IoC容器自动扫描所有的Bean并组装他们。

  • 1.同上面的1
  • 2.同样定义同上面的JavaBean,只不过在JavaBean增加@Component注解,来标示是一个JavaBean组件

(1)定义一个RegisterService

@Componentpublic class RegisterAnnotationService {    //   @Autowired将指定类型的Bean直接注入到指定的字段    @Autowired    private MessageAnnotationService messageAnnotationService;}

通过 @Autowired将指定类型的Bean直接注入到指定的字段。当然@Autowired也可以注解List<JavaBean>集合中,这样每增加一个同类型的JavaBean,都会被IoC容器自动装配到该集合中。如果要设置JavaBean被装配的顺序,则可通过在组件上增加@Order(1)、@Order(2)……

默认情况下,当给定字段标记了 @Autowired,如果IoC容器没有找到对应的JavaBean,则会抛出NoSuchBeanDefinitionException异常,所以可以增加@Autowired(required=false)来避免该异常。

(2)定义MessageService

@Componentpublic class MessageAnnotationService {}

通过增加上面的两个注解的方式,就完成了JavaBean之间的配置规则。

默认的将JavaBean标记为@Component,那么IoC容器会自动创建一个单例,即容器初始化的时候创建JavaBean,容器销毁的时候销毁。在整个容器运行期间,getBean()获取的是一个实例。

其实可以通过@Scope来标记该实例的作用域:即@Scope(value = "singleton")或@Scope( "singleton"),该value对应的有四种作用域

singleton :唯一的bean实例,默认的为单例。即getBean()获取的是一个实例。

prototype:每次容器返回的都是一个新的实例。即getBean()获取的都是一个新的实例。

request:每次Http请求的时候都会产生一个新的实例,仅在当前request请求中有效。

session:每次Http请求的时候都会产生一个新的实例,仅在当前session内有效。

  • 3.通过读取注解来获得到IoC容器
@Configuration  //用来标明是一个配置类,在创建AnnotationConfigApplicationContext,需要传入该类@ComponentScan //用来告诉容器,自动扫描当前类所在的包以及子包,把所有标注为@Component的Bean都自动创建出来,并根据@Autowired进行装配public class RegisterAnnotationApplication {    public static void main(String[] args) {       ApplicationContext context = new  AnnotationConfigApplicationContext(RegisterAnnotationApplication.class);        RegisterAnnotationService service = context.getBean(RegisterAnnotationService.class);        //RegisterService service = (RegisterService)context.getBean("registerService");        User user = service.register("12345678901", "123456");        System.out.println("注册之后的用户名为:"   user.name);    }}

不同于通过XML文件的配置方式,在读取ApplicationContext的时候,需要将该类增加一个 @Configuration  用来标明是一个配置类(其实@Configuration可以用@Component来代替,也就是如果分不清这个组件具体什么作用,那就直接用@Component),在创建AnnotationConfigApplicationContext的时候,需要传入该类;增加@ComponentScan 用来告诉容器,自动扫描当前类所在的包以及子包,把所有标注为@Component的Bean都自动创建出来,并根据@Autowired进行装配。

运行项目结果和上面的一致。相关代码已经上传github:https://github.com/wenjing-bonnie/build-spring.git:对应的com/wj/springannotation下的相关代码。

3.Spring中的其他几种注解

1.JavaBean组件相关的注解

像之前大体有印象的一些@Controller/@RestController、@Service、@Respository等这些都是用来注解为JavaBean,只不过这是在后面的Spring MVC具有一些特殊功能的JavaBean,如果分不清该组件属于哪一种,就直接使用@Component来注解。

2.读取配置文件、资源文件等相关注解

  • (1)读取Resources下面的一些普通的文件

使用IoC容器,可以很方便的把这些文件引入进来,方便程序读取,省掉了很多繁琐的代码来获取InputStream。在Maven项目中,经常会将这些文件放置到Resources目录下,所以Spring框架就提供了org.springframework.core.io.Resource来可以直接读取到文件的InputStream

    @Value("readme.txt")    private Resource readmeTxt;

那么在项目中就可以通过readmeTxt.getInputStream()获取到该txt的inputstream。

  • (2)读取Resouces下的一些key/value结构的文件

经常有些配置文件是key/value形式的存在文件中,在使用上面的方式,显得不太方便,那么IoC容器还提供了更简便的方式来读取。通过添加@PropertySource注解的方式,就可以直接根据key来获取到对应的value。例如有一个配置文件config/application.properties的内容如下:

application.ipaddress = 192.168.110.118

我们只需要在需要读取该配置文件的组件上添加 @PropertySource("config/application.properties"),那么就可以通过key来得到对应的value值。

@Configuration@PropertySource("config/application.properties")public class ApplicationConfig {    @Value("${application.ipaddress}")    public String ipAddress;}

@Value("${application.ipaddress}"):为没有默认值的value,如果想给定默认值的话,则 @Value("${application.ipaddress:192.168.0.0}")。

  • (3)在其他组件中引用配置文件的相关内容

还是上面的例子,如果在其他地方也要引用config/application.properties里面的配置项,其实可以直接通过@Value("#{bean.property}")的方式来得到对应的配置项,bean就是ApplicationConfig的实例applicationConfig(该实例不需要引入,只是组件名的首字母小写)的ipAddress属性值引入到OtherAnnotation。

@Componentpublic class OtherAnnotation {    @Value("#{applicationConfig.ipAddress}")    public String ipAddress;}

通过该注解方式,在OtherAnnotation中可以不用引入config/application.properties就可以读取到定义在ApplicationConfig里面的配置项。与(2)不同的是,在(2)中使用的是@Value("${key:defaultValue}")的形式读取配置文件中的值,而在OtherAnnotation中通过@Value("#{bean.property}")读取在ApplicationConfig中读到的配置项。

四 JavaBean生命周期的监听

当我们将一个JavaBean添加到IoC容器时,有的时候可能需要在容器初始化该JavaBean的时候监听消息等,在容器关闭的时候清理资源。那么就可以通过在该JavaBean只能够定义两个方法,在项目中引入javax.annotation依赖,通过javax.annotation的@PostContruct和@PreDestroy添加到上述的两个方法中。其过程如下:

(1)在pom.xml添加javax.annotation依赖

        <dependency>            <groupId>javax.annotation</groupId>            <artifactId>javax.annotation-api</artifactId>            <version>1.3.2</version>        </dependency>

(2)在MessageAnnotationService中需要承载初始化和销毁的方法上添加@PostContruct和@PreDestroy

public class MessageAnnotationService {    @PostConstruct    public void init() {        System.out.println("MessageAnnotationService init");    }    @PreDestroy    public void destroy() {        System.out.println("MessageAnnotationService destroy");    }}

这样在IoC容器初始化和销毁的时候,就会看到对应的方法的调用 。

五 总结

1.Spring的核心功能就是IoC容器,提供组件的创建和装配,只需要定义配置规则,IoC容器会自动完成所有的过程;

2.可以通过XML文件和注解两种方式来定义组件之间的配置规则;

3.终于搞明白了项目中为什么有那么多bean的配置文件;

4.使用@Component来注解一个类为组件,那么IoC容器在启动的时候,就会自动初始化该组件;

5.可以用@Scope来指定组件实例的作用域,是单例还是每次都是一个新的实例;

6.一个ApplicationContext就是一个IoC容器,可以从ApplicationContext中通过getBean()来获取到对应的组件实例;

7.使用javax.annotation可以在组件初始化或者销毁的时候做一些事情;

8.可以使用Resource轻松得到resouces下的文件的inputStream;

9.可以通过 @PropertySource的方式轻松得到配置文件的key/value;

10.之前有点印象的@Controller/@RestController、@Service、@Respository等其实都是一些组件,只不过是一些拥有特殊功能的组件。

每天都在进步一点,加油!!!

来源:https://www.icode9.com/content-4-862751.html

(0)

相关推荐