1. 程式人生 > >spring系列(一)——簡介和IOC

spring系列(一)——簡介和IOC

Spring簡介

Spring是輕型框架,有ioc(控制反轉,最常見的方式叫做依賴注入(Dependency Injection,簡稱DI))和aop(面向切面)兩個重要功能

IOC的思路是,不用程式碼建立物件,而配置物件(bean),在容器載入時,載入所有物件,要使用這些物件時,從容器物件中去獲得。

Spring配置使用

配置檔案

Spring容器的載入需要讀取Spring的配置檔案,檔案是xml格式,可以定義bean。一個簡單的Spring配置檔案test1.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.xsd">
    	
    	<bean id="test" class="java.lang.String">
    		<constructor-arg value="張三" />
    	</bean>
</beans>
xmlns是beans的名稱空間,xmlns:xsi是它的一個屬性叫做xsi,xsi:schemaLocation是xml編碼所要遵守的格式。

隨著載入的組建/框架的增多,xmlns這裡也要新增新的屬性

比如要使用註解注入,就要加上

xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation編碼格式中加上
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd 
比如配置檔案中要寫dubbo的配置檔案,就要加上
xmlns:dubbo=”http://code.alibabatech.com/schema/dubbo”
xsi:schemaLocation編碼格式中加上
http://code.alibabatech.com/schema/dubbo          http://code.alibabatech.com/schema/dubbo/dubbo.xsd

如何載入Spring配置檔案

java類

在普通的類中,可以通過程式碼的方式載入Spring的配置檔案,得到Spring的容器物件,並獲得容器物件中的bean物件

public class TestQ {
	public static void main(String[] args) {
		ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("file:F:/workspace1.8/sdz-web/WebContent/WEB-INF/test1.xml");
		context.start();
		System.out.println((String)context.getBean("test"));
	}
}
可以把程式碼重構一下
public class TestQ {
	
	private static ClassPathXmlApplicationContext context;
	
	static {
		context = new ClassPathXmlApplicationContext("file:F:/workspace1.8/sdz-web/WebContent/WEB-INF/test1.xml");
		context.start();
	}
	
	public static void main(String[] args) {
		System.out.println(context.getBean("test"));
	}
}

執行結果

web

在javaweb中可以通過配置web.xml來實現Spring容器的載入,需要配置contextConfigLocation引數,值是spring配置檔案,並配置spring的監聽器。當專案執行時,spring監聽器會載入spring的配置檔案,完成容器載入。

<context-param>
	<param-name>contextConfigLocation</param-name>
	<param-value>WEB-INF/spring-conf.xml</param-value>
</context-param>
<listener>
	<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

Bean的構造

Spring中<bean>實際上就是呼叫類的構造器。我給類的構造器加上列印語句,在spring中配置該類的bean,載入spring配置檔案,可以發現呼叫了構造器的列印語句,故<bean>的實現是呼叫類的構造器。例子如下

Spring配置檔案

<?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.xsd">
    	<bean id="testQ" class="com.lc.consumer.TestQ" />
</beans>
Java類
public class TestQ {
	private static ClassPathXmlApplicationContext context;
	
	static {
		context = new ClassPathXmlApplicationContext("file:F:/workspace1.8/sdz-web/WebContent/WEB-INF/test1.xml");
		context.start();
	}
	
	public TestQ() {
		System.out.println("TestQ構造器");
	}
	public static void main(String[] args) {
	}
}
執行結果

Bean傳參賦值

Spring物件(bean)的賦值。SpringBean的屬性賦值常見有兩種方式property和constructor-arg,以Student類來舉例。

public class Student {
	private String name;
	public Student() {}
	public Student(String name) {
		this.name = name;
	}
	public void setName(String name) {
		this.name = name;
	}
}

property

property是set注入,實際上呼叫物件的set方法,配置標籤是property。當找不到對應set方法時,會丟擲異常:NotWritablePropertyException

<bean id=”stu” class=”com.lc.consumer.Student” >
	<property name=“name” value=”xxx”” />
</bean>
等同java程式碼:
Student stu = new Student();
stu.setName("xxx");

constructor-arg

constructor-arg是構造注入,實際上是構造器傳參,配置標籤是constructor-arg。

<bean id="stu" class="com.lc.consumer.Student">
         <constructor-arg value="xxx" />
</bean>

等同java程式碼:

Student stu = new Student("xxx");

同時spring支援通過factory-bean來賦值傳參,下面是通過SimpleDateFormat給Date傳參

<bean id="simpleDateFormat"class="java.text.SimpleDateFormat" >
         <constructor-arg value="yyyy-MM-dd" />
</bean>
<bean id="employers" class="com.lc.ioc.Employers">
         <property name="workStart" >
                   <bean factory-bean="simpleDateFormat" factory-method="parse">
                            <constructor-arg value="2016-05-18" />
                   </bean>
         </property>
</bean>

獲得bean物件

通過程式碼獲取

普通Java類中,可通過載入配置檔案得到的Spring容器上下文物件獲得

ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml配置地址");
context.start();
Student stu = (Student)context.getBean("stu");

在web專案中,可以通過request得到Spring容器上下文物件,接著根據上下文物件過的

ServletContext sc =request.getSession().getServletContext();  
ApplicationContext ac1 =WebApplicationContextUtils .getRequiredWebApplicationContext(sc);
ac1.getBean("stu"); 

註解注入

在實際工作中一般採用零配置的方式,完成註冊bean功能。將java物件前加上'@Autowired'、'@Resource'註解,會自動在Spring容器中尋找class型別相同或class型別相同id與物件屬性相同的bean,並賦值。Spring註解注入不支援靜態屬性。

使用方法

1.添加註入配置AutowiredAnnotationBeanPostProcessor,它的作用是查詢spring容器中所有的bean,如果發現bean中存在'@Autowired'、'@Resource'註解,就根據要注入class型別,首先尋找Spring容器中是否存在相同class型別的bean:

若找到在一個,便賦值,

若找到多個,則找到id與要注入的屬性名相同的bean注入

若存在多個,也沒有找到id與與要注入的屬性名相同的bean,它會丟擲異常NoUniqueBeanDefinitionException: xxx expected single matching beanbut found 2: xxx,xxx。

注意:帶注入註解的類本身必須已經註冊成Spring的bean。

<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>

2.使用掃描注入配置<context:component-scan>,它會掃描指定包下所有的類,發現類帶有'@Component'、'@Service'、'@Controller'之中的一個註解時,會自動為這個類註冊bean,將所有帶註解的類都註冊bean之後,接著去查詢所有bean,尋找'@Autowired','@Resource'註解去注入。配置它可以省略AutowiredAnnotationBeanPostProcessor配置。這裡也可以加上<context:exclude-filter/>、<context:include-filter />,意思是不註冊某種註解的類、只註冊某種註解的類。

<context:component-scanbase-package="com.lc.consumer" />

3.使用配置<dubbo:annotation>,這是dubbo的掃描標籤,與<context:component-scan>功能類似,它除了會掃描帶有'@Component'、'@Service'、'@Controller'註解的類之外,它還會掃描帶有”@Service”(dubbo的service標籤)釋出服務,它支援的注入註解除了'@Autowired','@Resource'之外,還支援'@Reference'消費服務。同樣,配置<dubbo:annotation>,可以不配置<context:component-scan>,如果既配置<context:component-scan >、又配置<dubbo:annotation>,也不會註冊兩份bean。

<dubbo:annotationpackage="com.lc.consumer" />