spring(bean初始化、销毁、注入,作用域)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/belovehejian/article/details/78787078

IOC:控制反转,也称为依赖注入(DI)。这是一个过程。通常我们需要一个对象的时候,是主动创建对象,并且主动传入到需要使用该对象的地方。而IOC则是由容器创建对象,注入到我们需要使用该对象的位置,两者相比,一个主动,一个被动,被动的则是称为依赖注入(控制反转,由主动创建改为被动注入)。IOC容器读取配置元数据配置、组装、并实例化bean。配置元数据有3种方式

  1. web.xml方式:可用<bean id="" class=""></bean>,其中 id不是必须的。它是一个属性,用于标识bean的定义,class属性为bean的,使用类的全限定名。该<bean/>标签内还可以有多个属性,具体请查看文档。
  2. java注释:可用@Configuration、@Bean、@Import、@DependsOn。
  3. java代码:可用@Configuration、@Bean、@Import、@DependsOn。

bean:构成应用程序骨干,并由Spring IOC管理的对象称之为Bean。bean也是一个组装、实例化并由Spring IOC管理的一个对象。bean 的命名约定遵循 java 变量命名的约定。bean 还可以定义别名,如:

<!-- 定义bean -->
	<bean id="userController" class="com.xh.spring.project.controller.user.UserController"></bean>
	<!-- 别名标签中name属性为定义bean时的id,alias是为该bean指定的别名 -->
	<alias name="userController" alias="user"/> 
如果使用JAVA注释的方式定义bean,则@Bean标签内可以指定名称。bean 默认的创建方式是调用该类的构造器创建的。

也可通过静态工厂方法来创建实例 bean,这种方法指定的初始化方法(必须无参数)、销毁方法(必须无参数)、必须在要被创建bean实例的类当中,如:

public class TestBean {
	public TestBean() {
		System.out.println(this + "-------------------------------------------constructor method call()......");
	}
	public void initMethod() {
		System.out.println(this + "调用----init method call()......");
	}
	public void destroy() {
		System.out.println(this + "调用 --------destroy method call()......");
	}

}

工厂方法(参数可选):

public static TestBean getTestBean(String name){
		System.out.println("=========================factory method call()......" + name);
		return new TestBean();
	}

配置文件:

<!-- factory-method指定静态工厂方法,class指定静态方法所在的类 init(bean创建之后调用)以及destroy(销毁时调用)分别指定初始化与销毁方法
		工厂方法可以有参数,参数通过这种方式可以指定 <bean><constructor-arg index="0" value="zhangsan"/></bean>-->
	<bean id="testBean" factory-method="getTestBean" 
						class="com.xh.spring.project.controller.test.BeanFactory" 
						init-method="initMethod"
						destroy-method="destroy">
						<constructor-arg index="0" value="zhangsan"/>
						</bean>

也可使用注解的方式:

package com.xh.spring.project.controller.test;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

import org.springframework.stereotype.Component;

@Component("testBean")
public class TestBean {
	
	public TestBean() {
		System.out.println(this + "-------------------------------------------constructor method call()......");
	}
	
	@PostConstruct
	public void initMethod() {
		System.out.println(this + "调用----init method call()......");
	}
	
	@PreDestroy
	public void destroy() {
		System.out.println(this + "调用 --------destroy method call()......");
	}

}


还可以利用已有的 bean 对象来创建新的 bean 对象,只需要在配置文件当中配置

<!-- factory-bean指定用哪个bean来创建新的bean,factory-method指定用bean中的哪个方法来创建(方法必须位于
		factory-bean指定的bean的具体类当中,方法为 实例方法) -->					
	<bean id="testOtherBean" factory-bean="testBean" factory-method="getTestOtherBean"></bean>

testBean中的内容:

package com.xh.spring.project.controller.test;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

import org.springframework.stereotype.Component;

public class TestBean {
	public TestBean() {
		System.out.println(this + "-------------------------------------------constructor method call()......");
	}
	public void initMethod() {
		System.out.println(this + "调用----init method call()......");
	}
	public void destroy() {
		System.out.println(this + "调用 --------destroy method call()......");
	}
	public TestOtherBean getTestOtherBean() {
		System.out.println("----------------------------------factory method call()......");
		return new TestOtherBean();
	}
}


bean的初始化、销毁、回调函数

上例中,在创建 bean 的时候,指定了初始化、销毁 bean 时的回调函数。上例是设置单个 bean 的回调函数。

还可以为所有的bean设置指定的初始化、销毁、的回调方法。只需要在顶层  <beans> 标签当中加入,default-init-method、default-destroy-method,利用该标签指定初始化回调函数、销毁回调函数的函数名。Spring IOC容器会识别该属性,当一个 bean 被创建组装时,如果该 bean 有这样一个方法,它会在适当的时间调用这个方法(Spring 容器保证一个配置好的初始化回调函数在一个 bean 被提供了所有的依赖关系之后被立即调用。这意味着AOP拦截器还没有被应用到 bean,因为目标 bean 首先被创建,然后才会使用代理)。

Spring 有3个控制 bean 生命周期的选项,InitializingBean、DisposableBean回调接口,init()和destrot()方法,以及 @PostConstruct  @PreDestroy注释。

如果为同一个bean配置了多个生命周期机制,并且多个机制都具有相同的方法名,那么这些方法,将只执行一次。如果多个生命周期机制使用不同的初始化方法,调用顺序为(以初始化回调为例,初始化回调、销毁回调的顺序是一样的):

用注释的方法,@PostConstruct

afterPropertiesSet(方法),这是InitializingBean接口中的方法。

自定义配置的init()方法。

依赖注入

依赖注入有2种

  1. 基于构造器的依赖注入
  2. 基于setter的依赖注入

还有很多基于上面2种混合使用的注入案例,可以查看Spring官方文档学习。

构造器注入(推荐使用):

package com.xh.spring.project.controller.test;

public class DemoBean {
	
	private String name;
	private int age;
	
	public DemoBean(String name, int age) {
		this.name = name;
		this.age = age;
	}

}


在注入具体值时,使用构造器注入时,如果用type属性,那么顺序将不再那么重要,spring将会自动的寻找匹配的类型,将具体值注入进去。有些类型,如:string 则必须要全限定类名,否则无法注入进去

<bean id="demoBean" class="com.xh.spring.project.controller.test.DemoBean">
		<constructor-arg type="int" value="29"/>
		<constructor-arg type="java.lang.String" value="zhangsan"/>
	</bean>

如果使用index属性,那么书写顺序将严格按照构造器当中参数的顺序书写,否则将会报错。索引属性 index 从 0 开始

<bean id="demoBean" class="com.xh.spring.project.controller.test.DemoBean">
		<constructor-arg index="0" value="zhangsan"/>
		<constructor-arg index="1" value="29"/>
	</bean>

还可以使用构造器当中具体的属性名称充当构造注入时的 name 属性

<bean id="demoBean" class="com.xh.spring.project.controller.test.DemoBean">
		<constructor-arg name="age" value="29"/>
		<constructor-arg name="name" value="zhangsan"/>
	</bean>

还可以使用 p 命名空间,以及 c 命名空间 来进行注入,当使用 p 时,注入基本值,使用 p:属性名=“值”, 注入其他bean属性时 p:属性名-ref=“bean名称”。c 命名空间与之类似

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource"
        destroy-method="close"
        p:driverClassName="com.mysql.jdbc.Driver"
        p:url="jdbc:mysql://localhost:3306/mydb"
        p:username="root"
        p:password="masterkaoli"/>
</beans>

<bean id="bar" class="x.y.Bar"/>
    <bean id="baz" class="x.y.Baz"/>

    <!-- traditional declaration -->
    <bean id="foo" class="x.y.Foo">
        <constructor-arg ref="bar"/>
        <constructor-arg ref="baz"/>
        <constructor-arg value="[email protected]"/>
    </bean>

    <!-- c-namespace declaration -->
    <bean id="foo" class="x.y.Foo" c:bar-ref="bar" c:baz-ref="baz" c:email="[email protected]"/>

Spring容器在容器创建时验证每个 bean 的配置,在实际创建 bean 之前,bean 属性本身不会被实例化,bean 是单例的,(默认的设置是)是预先实例化,在创建容器的时候创建的。也可以在请求的该bean的时候创建(懒惰初始化)。


spring的自动装配有4种模式

  1. 默认的。也就是直接在定义bean的时候,在配置文件当中利用 ref 属性指定需要装备进去的bean。
  2. 按名称。也就是在使用注解注入的时候,指定需要注入的 bean 的名称,spring 会自动去寻找指定名称的 bean 进行装配
  3. 按类型。当需要装配时,如果IOC容器当中只有一个符合需要注入的 bean 类型,则允许按类型自动装配。如果存在多个,则抛异常。如果没有匹配的bean,则不做任何事。
  4. 类似于byType,但适用于构造函数参数。如果容器中没有一个构造函数参数类型的bean,则会引发致命错误。

bean的作用域

创建一个 bean 也是基于配置文件,创建一个该 bean 定义所对应的类的实例。创建 bean 的实际操作由 spring 操作,但是bean的各种属性配置,则有我们来实现。而作用域也是如此。spring 支持7种作用域

  1. singleton:每个 Spring IOC 容器将单个 bean 定义作用域为单个对象实例。这个单例 bean 被缓存在这样的 sigleton bean 缓存池中,所有对该bean的请求都会从该缓存池中获取该 bean 对象并返回。
  2. ptototype:每次获取都将产生一个新的 bean 实例。spring 不在管理原型 bean 的整个生命周期,但 spring 在创建 bean 的时候 依然会调用初始化生命周期的回调方法,但是却不在调用配置的销毁生命周期的方法。bean对象 的使用者必须自己清理 bean 的引用,释放其所持有的资源。
  3. requet:将单个bean定义作用与单个HTTP请求的生命周期,也就是说每个HTPP请求都有自己的bean实例。这个实例是在单个 bean 定义的后面创建的。只有在网络感知的Spring的上下文中才有效。
  4. session
  5. globalSession
  6. application
  7. websocket



spring相对来说

是很主要单独



猜你喜欢

转载自blog.csdn.net/belovehejian/article/details/78787078