Spring容器、Spring对象及SpringIOC

Spring:是一个开源的轻量级的应用框架,其目的是用于简化企业级应用程序开发,降低侵入性;其本质是管理软件中的对象,及创建对象和维护对象之间的关系。
Spring容器:用来管理对象;本身也是对象;是IOC的核心

在spring中,任何的Java类和JavaBean都被当做Bean处理,这些Bean通过容器管理和使用;Spring容器实现了IOC和AOP机制,这些机制可以简化Bean对象创建和Bean对象直接的解耦;Spring容器有BeanFactory和ApplicationContext两种类型。

JavaBean:一种简单规范的Java对象

什么是JavaBean?
满足如下规范的类:
1.有package
2.有默认构造器
3.实现序列化接口Serializable
4.有get/set方法

Spring容器的实例化:ApplicationContext集成自BeanFactory接口,拥有更多的企业级方法,推荐使用该类,实例方法如下:

//加载项目classpath下的配置文件实例化
ApplicationContext ctx = new ClassPathXmlApplicationContext("app.xml");

Spring容器对Bean(对象)的管理:

Bean的实例化:

1.构造器方式:

<!-- Springc创建对象 -->
	<!-- 1.通过构造器创建对象:class是要创建的对象的类型 -->
	<bean class="java.util.ArrayList" id="obj1"></bean>
//在junit的测试代码中测试
        List list = (List) ctx.getBean("obj1");
		System.out.println(list);

注:id或name属性用于指定Bean名称,用于从Spring中查找这个Bean对象;class用于指定Bean类型,会自动嗲用无参构造器创建对象。

2.静态工厂方法:

<!-- 2.通过静态工厂方法创建对象,调用某类的静态方法来创建对象;class:要调用的类,factory-method:要调用的静态方法 -->
	<bean class="java.util.Calendar" factory-method="getInstance" id="obj2"></bean>
//测试代码
    Calendar c = (Calendar) ctx.getBean("obj2");
		System.out.println(c);
		Date s = c.getTime();
		System.out.println(s);

注:id属性用于指定Bean名称;class属性用于指定工厂类型;factory-method属性用于指定工厂中创建Bean对象的方法,必须用static修饰的方法。

3.实例工厂方法:

<bean factory-bean="obj2" factory-method="getTime" id="obj3"></bean>
 Date d = (Date) ctx.getBean("obj3");
		System.out.println(d);

注:id用于指定Bean名称;factory-bean属性用于指定工厂Bean对象;factory-method属性用于指定工厂中创建Bean对象的方法。

Bean的命名:

在spring容器中,每个Bean都需要有名字(即标识符),该名字可以用<bean>元素的id或者那么属性执行。

Bean的别名:为以定义好的Bean,在增加另外一个名字引用,可以使用<alias>指定;如:

<alias name="fromName" alias="toName>
Bean的作用域:

Spring在容器实例化Bean时,可以创建一下作用域的Bean对象:

singleton:在每个Speing IOC容器中一个bean对应一个对象实例,默认项;

prototype:一个bean定义对应多个对象实例;

request:在一次HTTP请求中,一个bean定义对应一个实例,仅限于Web环境;

session:在一个HTTP Session中,一个bean定义对应一个实例,仅限于Web环境;

global Session:在一个全局的HTTP Session中,一个bean定义对应一个实例;仅在基于prothet的Web应用中才有意义;

上面的Bean作用域,可以通过<bean>定义的scope属性指定;如下:

<bean class="java.util.HashMap" id="obj4" scope="singleton"></bean>
    /**
	 * bean的作用域:
	 * 每个bean在容器中默认都是单例的
	 */
	@Test
	public void test4(){
		//1.创建Spring容器
		ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
		//获取bean
		Map map1 = (Map) ctx.getBean("obj4");
		Map map2 = (Map) ctx.getBean("obj4");
		System.out.println(map1==map2);
	}
管理Bean的生命周期:就是让spring自动调用该bean的初始化和销毁方法
<bean class="bean.Example" id="exa" init-method="init" scope="singleton" lazy-init="true"></bean>

init-method:声明销毁方法,在容器关闭时自动调用
destory-method:声明销毁方法,在容器关闭时自动调用。但是只对单例的bean有效

//测试代码 
	/**
	 * 容器管理bean生命周期
	 */
	@Test
	public void test5(){
		//1.创建容器
		//classPathXmlApplicationContext继承于AbstractApplicationContext
		//后者实现了ApplicationContext。
		//AbstractApplicationContext里面生命了关闭容器的方法close
		AbstractApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
		System.out.println("1-----");
		//获取bean
		Example exa = (Example) ctx.getBean("exa");
		System.out.println(exa);
		System.out.println("2---");
		ctx.close();
	}
Bean延迟实例化:适用于使用频率很低的单例对象
<bean id="exampleBean" lazy-init="true" class="com.foo.ExampleBean"/>

如果不想让 singleton bean在ApplicationContext初始化时就被提前实例化,可以使用延迟实例化。

lazy-init:延迟初始化,即在容器创建时并不创建bean,而是在获取bean才创建,将bean创建的时机推迟了,只对单例的bean有效。

Spring容器工作过程:

SpringIOC:

ioc全称是Intersion of Control,被译为控制反转;指的是程序中对象的获取方式发生反转,由最初的new方式创建,转变为由第三方框架创建、注入(DI),它降低了对象之间的耦合度。

Spring容器是采用DI方式石像IOC控制,IOC是Spring框架的基础和核心;

DI全称Dependency Injection,被称依赖注入;基本原理就是将一起工作具有关系的对象,通过构造方法参数或方法参数传入建立关联,因此容器的工作就是创建bean时注入那些依赖关系。

IOC是一种思想,而DI是实现IOC的主要技术途径;DI主要有两种注入方式,即Setter注入和构造器注入;

setter注入:通过调用无参构造器或无参static工厂方法实例化bean之后,调用该bean的setter方法,即可实现setter方式的注入

<!-- 1.setter注入:通过bean的set方法,给它注入参数 -->
	<bean class="bean.Computer" id="computer">
		<property name="mainboard" value="技嘉"/>
		<property name="hdd" value="希捷"/>
		<property name="ram" value="金士顿"/>
	</bean>
/**
	 * 依赖注入 -setter注入
	 */
	@Test
	public void test6(){
		//创建容器
		ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
		Computer com = (Computer) ctx.getBean("computer");
		System.out.println(com);
		System.out.println(com.getHdd()+";"+com.getHdd()+";"+com.getRam());
	}
package bean;

public class Computer {
	private String mainboard;
	private String hdd;
	private String ram;
	public String getMainboard() {
		return mainboard;
	}
	public void setMainboard(String mainboard) {
		this.mainboard = mainboard;
	}
	public String getHdd() {
		return hdd;
	}
	public void setHdd(String hdd) {
		this.hdd = hdd;
	}
	public String getRam() {
		return ram;
	}
	public void setRam(String ram) {
		this.ram = ram;
	}
	
}

构造器注入:基于构造器的注入是通过调用带参数的构造器来实现的,容器在bean被实例化的时候,根据参数类型执行相应的构造器;构造器注入,可以强制给bean注入某些参数,比Setter注入更严格,往往是为了强制注入这些参数。

xml和测试:

<bean class="bean.MobilePhone" id="phone">
		<constructor-arg index="0" value="ARM"/>
		<constructor-arg index="1" value="4G"/>
	</bean>
	@Test
	public void test7(){
		//创建容器
		ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
		MobilePhone phone = (MobilePhone) ctx.getBean("phone");
		System.out.println(phone);
		System.out.println(phone.getCpu()+";"+phone.getRam());
	}

实体类:

package bean;

import java.io.Serializable;

public class MobilePhone implements Serializable{
	
	private String cpu;
	private String ram;
	
	
	public MobilePhone(String cpu, String ram) {
		this.cpu = cpu;
		this.ram = ram;
	}
	public String getCpu() {
		return cpu;
	}
	public void setCpu(String cpu) {
		this.cpu = cpu;
	}
	public String getRam() {
		return ram;
	}
	public void setRam(String ram) {
		this.ram = ram;
	}
	
}

自动装配:Spring Ioc容器可以自动装配(autowire)相互协作bean之间的关联关系,autowire可以针对单个bean进行设置,autowire的方便在于减少了xml的注入配置;在xml配置文件中,可以在<bean/>元素中使用autowire属性指定自动装配规则,一共有5种类型值

<!-- 自动装配:Spring在创建bean时,可以根据类型或名称,从容器中找到匹配的bean,设置给这个bean属性,需要创建对应的Student类 -->
	<bean class="bean.Student" id="student" autowire="byType"></bean>
/**
	 * 自动装配
	 */
	@Test
	public void test8(){
		//创建容器
		ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
		Student s = (Student) ctx.getBean("student");
		System.out.println(s.getComputer().getMainboard());
		System.out.println(s.getPhone().getCpu());
	}

no:禁用自动装配;

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

byType:如果容器中存在一个与指定属性类型相同的bean,那么将与该属性自动装配;

constructor:与byType的方式类似,不同之处在于它应用于构造参数

autodetect:通过bean类来决定是使用constructor还是byType方式进行自动装配,如果发现默认的构造器,那么将使用byType方式;

参数值注入:

<!-- 参数值注入 -->
	<bean class="bean.Message" id="msg">
		<!-- 注入基本值:基本类型、封装类型、String类型 -->
		<property name="id" value="1"/>
		<property name="name" value="zhangsan"/>
		<property name="sal" value="50000.00"/>
		<!-- 注入bean(前提是都在容器之中,必须由容器创建);name:要注入的属性的名称 ;ref:注入的bean的ID -->
		<property name="phone" ref="phone"/>
		<!-- 注入集合List、Set、Map、Properties -->
		<property name="cities">
			<list>
				<value>北京</value>
				<value>上海</value>
				<value>广州</value>
			</list>
		</property>
		<property name="score">
			<map>
				<entry key="张三" value="101KG"/>
				<entry key="李四" value="102KG"/>
			</map>
		</property>
		<property name="params">
			<props>
				<prop key="user">system</prop>
				<prop key="password">dream</prop>
			</props>
		</property>
	</bean>
	/**
	 * 参数值注入
	 */
	@Test
	public void test9(){
		//创建容器
		ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
		Message msg = (Message) ctx.getBean("msg");
		System.out.println(msg.getId());
		System.out.println(msg.getName());
		System.out.println(msg.getSal());
		System.out.println(msg.getPhone().getCpu());
		System.out.println("城市:"+msg.getCities().get(0));
		System.out.println("体重:"+msg.getScore().get("张三"));
		System.out.println("参数:"+msg.getParams().getProperty("user"));
	}

基于注解的依赖注入:

说到注解不得不聊一下组件扫描;组件扫描就是制定一个包路径,Spring会自动扫描该包及其子包所有组件类,当发现类定义前有特点的注解标记是,就将该组件纳入到Spring容器,等价于原有XML配置中的<bean>定义功能;组件扫描可以替代大量XML配置的<bean>定义。

指定组件扫描路径:

<!--使用组件臊面,首先需要在XML配置中指定扫描父级package路径-->
<context:component-scan base-package="org.example"/>

上面配置,容器会自动扫描org.example包及其子包下所有组件,并实例化为bean。

自动扫描的注解标记:只有在组件类定义前面有一下注解标记时,才会扫描到Spring容器中去。

@Component:通用注解

@Named:通用注解

@Repository:持久层组件注解

@Service:业务层组件注解

@Controller:控制层组件注解

自动扫描组件的命名:(两种)

@Component  //默认id为小写开头的类名
public class ExampleBean implements Serializable{
}   

@Component("example")  //自定义id
public class ExampleBean implements Serializable{
}       

自定组件的作用域:

@Component
@Scope("prototype")
public class ExampleBean implements Serializable{

}

注:通常受spring管理的组件,默认的作用域是“singleton”,如果需要其他的可用@Scope注解。

自定初始化和销毁的回调:

/**
 * @author dream-it
 * 演示 组件扫描
 */
//通用的注解,表示什么地方都能用,加了之后spring会将Student当bean来管理
//配置文件会自动生成一个bean,默认的ID是首字母小写之后的类名
@Component("stu")
//表示作用域
@Scope("singleton")
//延迟加载
@Lazy(true)
public class Student {
	
	//初始化方法
	@PostConstruct
	public void init(){
		System.out.println("Student的init()...");
	}
	
	//销毁方法
	@PreDestroy
	public void destory(){
		System.out.println("Student的销毁");
	}
	
	public Student() {
		System.out.println("Student的无参构造器...");
	}
	
}

依赖注入(使用注解):主要由3中方式;

1.AutoWired和Qualifier(分为写在构造器和set方法前面两种)

@Autowired写在构造器前面,声明需要为其注入bean

@Qualifier写在参数前面,声明需要注入的bean的ID值

@Component("rest")
public class Restaurant {
	//这两个注解也可以直接添加到属性前面
	//此时对应的set方法可以不要,通过反射的机制来执行
	@Autowired
	//wt表示被注入的bean的ID
	@Qualifier("wtm")
	private Waiter wt;	

测试类:

	@Test
	//测试@AutoWired来完成注解
	public void test5(){
		ApplicationContext ctx = new ClassPathXmlApplicationContext("app.xml");
		Restaurant rest = ctx.getBean("rest",Restaurant.class);
		System.out.println(rest);
		Hotel hotel = ctx.getBean("hotel",Hotel.class);
		System.out.println(hotel);
	}

注意:注入的对象是单例时,@Qualifier可省略,此时,Spring按照类型匹配参数

@Autowired写在set方法前面,声明需要为其注入bean

@Qualifier写在参数前面,声明需要追的bean的ID值

@Component("rest")
public class Restaurant {
  private Waiter wt;
  @Autowired
  public void setWt(@Qualifier("wt") Waiter wt) {
  System.out.println("Res的set方法");		
  this.wt = wt;
}
2.@Inject注解:和@Autowired功能一直,但使用时需要额外导包

@Inject注解标记是Spring3.0开始增添的对JSR-330标准的支持,使用前需要添加JSR-330的jar包javax.inject-1.jar

@Inject注解用法和@Autowired一直,其中

1).@Inject等价于@Autowired;

2).@Named等价于@Qualifier

3.@Resource注解:(只能用于setter注入,但更简单,也更重要,因为一般都Setter注入)
@Component
public class Manager implements Serializable{
   private Computer computer;
   @Resource(name="computer")
   public void setComputer(Computer computer){
   this.computer = computer;
   System.out.println("Manager");
  }
}

注意:1.注入的对象单例时,(name=“computer”)可省略,此时,Spring安装类型匹配参数

          2.@Resource也可以写在属性上,作用和写在set方法上类似,但只会执行一行代码:this.computer = computer;

总结:

Spring容器就相当于是一个大的抽象工厂,在程序中创建对象是很复杂的,所以才会有相应的设计模式。Spring容器就相当于把对象拿过来用框架帮你进行管理,这样就大大的降低程序的耦合度;并且Spring容器实现了IOC和AOP的机制,让创建对象和扩展都得变得容易的,也符合开闭原则。并且运用SpringIOC的DI方式注入对象,也大大的降低了程序的耦合度。

猜你喜欢

转载自blog.csdn.net/huang_yx/article/details/79735951