天天看點

Spring DI(IOC)注釋用法通過配置檔案來配置Spring

注釋用法

@Required

用于setter方法上,它表明受影響的 bean 屬性在配置時必須放在 XML 配置檔案中,否則容器就會抛出一個BeanInitializationException 異常。
public class Student{
  private String name;
  private int age;

  @Required
  public void setAge(Integer age) {
     this.age = age;
  }
  public Integer getAge() {
     return age;
  }
  @Required
  public void setName(String name) {
     this.name = name;
  }
  public String getName() {
     return name;
  }
}
           
//xml配置檔案裡沒有配置age這個屬性,會報BeanInitializationException的異常。
<context:annotation-config/>
<bean id="student" class="Student">
  <property name="name" value="lph"/>
</bean>

           

@Autowired

預設按照類型方式進行bean比對

對屬性注釋,用來替代setter方法

對setter方法注釋

對構造函數注釋

public class Customer 
{
   @Autowired        //對屬性注釋
	private Person person;
	private int type;
	private String action;
	
   @Autowired        //對setter方法注釋
   public setPerson(Person person){
       this.persion=persion;
   }
	
	@Autowired       //對構造函數注釋
	public Customer(Person person) {
		this.person = person;
	}
}
           
//@Autowired注解是通過比對資料類型自動裝配Bean。	
	<bean id="CustomerBean" class="com.x'x'x'x.common.Customer">
		<property name="action" value="buy" />
		<property name="type" value="1" />
	</bean>

	<bean id="PersonBean" class="com.x'x'x'x.common.Person">
		<property name="name" value="xx" />
		<property name="address" value="address ABC" />
		<property name="age" value="29" />
	</bean>	
           
使用掃描器來掃描包,省去在配置檔案裡配置相關bean
<context:component-scan base-package="xxx.xxxx.xxxxxx.xxxx"/>
           

依賴檢查

預設情況下,@Autowired将執行相關檢查,以確定屬性已經裝配正常。當Spring無法找到比對的Bean裝配,它會抛出異常。要解決這個問題,可以通過 @Autowired 的“required”屬性設定為false來禁用此檢查功能。

public class Customer 
{
	@Autowired(required=false)//即使沒有比對的bean,spring也不會報錯
	private Person person;
	private int type;
	private String action;
	//getter and setter methods
}
           

@Qualifier

建立多個具有相同類型的 bean 時,想要用一個屬性隻為它們其中的一個bean進行裝配,使用 @Qualifier 注釋和 @Autowired 注釋通過指定哪一個真正的 bean 将會被裝配來消除混亂。
public interface Parent(){
	public void iAmParent(){}
}
           
@Component
public class mother implements Parent{
	public void iAmParent(){
		.......
}
           
@Component
public class father implements Parent{
	public void iAmParent(){
		.......
	}
}
           
@Service
public class SequenceServiceImpl implements SequenceService {
	
	//此處會報錯,因為parent有兩個實作類father和mother
	@Resource
	private Parent parent;
}
           
此時我們可以用@Qualifier
@Service
public class SequenceServiceImpl implements SequenceService {

//使用@Qualifier指定bean
@Qualifier(name="father")
 private Parent parent;
}
           

@Resource

JSR-250規範定義的注解

和@Autowired作用類似,隻不過@Autowired是byType的方式自動注入,@Resource預設自動注入的方式為byName

@Resource裝配順序:

 1. 如果同時指定了name和type,則從Spring上下文中找到唯一比對的bean進行裝配,找不到則抛出異常

 2. 如果指定了name,則從上下文中查找名稱(id)比對的bean進行裝配,找不到則抛出異常

 3. 如果指定了type,則從上下文中找到類型比對的唯一bean進行裝配,找不到或者找到多個,都會抛出異常

 4. 如果既沒有指定name,又沒有指定type,則自動按照byName方式進行裝配;如果沒有比對,則回退為一個原始類型進行比對,如果比對則自動裝配;

@Bean @Configuration @Import 來代替xml配置檔案

<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="helloBean" class="com.xxx.hello.impl.HelloWorldImpl">		
</beans>

**等效于以下JavaConfig的配置:**

@Configuration
public class AppConfig {	
    @Bean(name="helloBean")
    public HelloWorld helloWorld() {
        return new HelloWorldImpl();
    }	
}
           
<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-2.5.xsd">
 
	<import resource="config/customer.xml"/>
    <import resource="config/scheduler.xml"/>
 
</beans>

**效于 @Import 功能**

@Configuration
@Import({ CustomerConfig.class, SchedulerConfig.class })
public class AppConfig {}
           

Spring自動掃描組建

啟用Spring元件掃描功能。
<context:component-scan base-package="xx.xxx.xxxx"/>
           
使用@Component注釋來表示這是類是一個自動掃描元件。
@Component
public class CustomerDAO 
{
	@Override
	public String toString() {
		return "Hello , This is CustomerDAO";
	}	
}
           
DAO層,添加@Component,表明這也是一個自動掃描元件。
@Component
public class CustomerService 
{
	@Autowired
	CustomerDAO customerDAO;

	@Override
	public String toString() {
		return "CustomerService [customerDAO=" + customerDAO + "]";
	}
} 
           
要建立元件的自定義名稱,你可以這樣自定義名稱:
@Service("AAA")
public class CustomerService 
           
自動掃描的組建類型(都是@Component的意思),對class注解
@Repository – 表示在持久層DAO元件。
@Service – 表示在業務層服務元件。
@Controller – 表示在表示層控制器元件。
@Component – 訓示自動掃描元件。(不屬于以上三者的時候使用)
           
Spring過濾器元件自動掃描
//include-filter 包含
<context:componnet-scan base-package="xx.xx.xxx">
 <context:include-filter type="regex" expression="xx.xxx.*DAO.*">
</context>
//exclude-filter 不包含
           

通過配置檔案來配置Spring

基于構造函數的依賴注入

注入class
public class demo{
    Test test;
    public void demo(Test test){
        this.test=test;
    } }

<bean id="demo" class="demo">
       <constructor-args ref="test" />  
       <constructor-args ref="test2" />
</bean>

//聲明2個class的bean
 <bean id="test" class="test" />
 <bean id="test2" class="test2" />
           
注入其他類型的值
public class demo{    
    public void demo(String str,int num){
        .....
    } }

<bean id="demo" class="demo">
   <constructor-args type="java.lang.String" value="axxxx" />
   <constructor-args type="int" value="1" />
</bean>
           
通過索引注入
<bean id="demo" class="demo">
  <constructor-args index="0" value="axxxx" /> 
  <constructor-args index="1" value="1" />
</bean>
           

基于設定函數的注入

public class demo{
   public void test(String str){
   .......
   }
} 
<bean id="demo" class="demo">
  <property name="str" value="this is a String" />
</bean> 
           

注入集合

public class demo{    
	List array;
	HashMap map;
	Porperties prop; 
} 
           
//注入list
<bean id="demo" class="demo">
   <property name="array">
    <list>
	      <value>1</value>
	      <value>2</value>
    <list>
  </property> 
           
//注入map
<property name="map">
   <map>
       <entry key="1" value="a1"/>
       <entry key="2" value="a2"/>
   </map>
</property> 
           
//注入屬性
<property name="prop">
   <props>
      <prop key="key1">xxx</prop>
      <prop key="key2">bbb</prop>         
   </props>
</property> 
           

注入空值null

<bean><property name="asd"><null/></property></bean>
           

在Spring架構中,當一個類包含多個構造函數帶的參數相同,它總是會造成構造函數注入參數類型歧義的問題。

為了解決這個問題,應該為構造函數指定的确切資料類型,通過像這樣類型的屬性:

<bean id="CustomerBean" class="com.xxx.common.Customer">
	
		<constructor-arg type="java.lang.String">
			<value>xxx</value>
		</constructor-arg>
		
		<constructor-arg type="java.lang.String">
			<value>188</value>
		</constructor-arg>
		
		<constructor-arg type="int">
			<value>28</value>
		</constructor-arg>		
	</bean>
</beans>
           

自動裝配

1. 預設的模式

這是預設的模式,你需要通過 ‘ref’ 屬性來連接配接 bean。

<bean id="customer" class="com.yiibai.common.Customer">
       <property name="person" ref="person" />
</bean>
<bean id="person" class="com.yiibai.common.Person" />
           

2. 按屬性名稱自動裝配’

按屬性名稱自動裝配。在這種情況下,由于對“person” bean的名稱是相同于“customer” bean 的屬性(“person”)名稱,是以,Spring會自動通過setter方法将其裝配 – “setPerson(Person person)“.

<bean id="customer" class="com.yiibai.common.Customer" autowire="byName" />	
<bean id="person" class="com.yiibai.common.Person" />
           

3. 按屬性的資料類型自動裝配

通過按屬性的資料類型自動裝配Bean。在這種情況下,由于“Person” bean中的資料類型是與“customer” bean的屬性>(Person對象)的資料類型一樣的,是以,Spring會自動通過setter方法将其自動裝配。– “setPerson(Person person)“.

<bean id="customer" class="com.yiibai.common.Customer" autowire="byType" />
<bean id="person" class="com.yiibai.common.Person" />
           

注入日期到bean屬性

以下寫法會報錯
public class Customer {
	Date date;
	public Date getDate() {
		return date;
	}
	public void setDate(Date date) {
		this.date = date;
	}
}
           
<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-2.5.xsd">

	<bean id="customer" class="Customer">
		<property name="date" value="2015-12-31" />//直接傳string類型的值給value
	</bean>
</beans>

           

正确的方法

factory-bean

<bean id="customer" class="Customer">
	<property name="date">
       <bean factory-bean="dataFormat" factory-method="parse">
           <constructor-arg value="2015-12-31" />
       </bean>
   </property>
</bean>
           
CustomDateEditor
<bean id="dateEditor" class="org.springframework.beans.propertyeditors.CustomDateEditor">
		<constructor-arg>
			<bean class="java.text.SimpleDateFormat">
				<constructor-arg value="yyyy-MM-dd" />
			</bean>
		</constructor-arg>
		<constructor-arg value="true" />
	</bean>

	<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
		<property name="customEditors">
			<map>
				<entry key="java.util.Date">
					<ref local="dateEditor" />
				</entry>
			</map>
		</property>
	</bean>

	<bean id="customer" class="Customer">
		<property name="date" value="2015-12-31" />
	</bean>
           

PropertyPlaceholderConfigurer

在聲明bean配置檔案和提供一個PropertyPlaceholderConfigurer映射到“database.properties”屬性檔案。
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
	<property name="location">
		<value>database.properties</value>
	</property>
</bean>
<bean id="dataSource" 
       class="org.springframework.jdbc.datasource.DriverManagerDataSource">
   <property name="driverClassName" value="${jdbc.driverClassName}" />
   <property name="url" value="${jdbc.url}" />
	<property name="username" value="${jdbc.username}" />
	<property name="password" value="${jdbc.password}" />
</bean>
           

Bean的切面處理

init-method 指定一個方法,在執行個體化 bean 時,調用該方法。

destroy-method 指定一個方法,從容器中移除 bean 之後,調用該方法。

singleton 和 prototype的差別( http://wiki.jikexueyuan.com/project/spring/bean-scopes.html)

<bean id="..." class="...." 
init-method="..." (destroy-method)
scope="..."
lazy-init="..." 
destroy-method="..." />
           
public example implements InitializingBean{
 //實作InitializingBean接口,bean 初始化時可調用的初始化方法
  public void do(){}
}

public example implements DisposableBean{
 //實作DisposableBean接口,bean 銷毀時可調用的初始化方法
  public void do(){}
}
           

兩種後處理方法

Bean後處理器

Bean後處理器會在Bean執行個體建立成功之後,對Bean執行個體進行進一步的增強處理。

Bean後處理器必須實作BeanPostProcessor接口,同時必須實作該接口的兩個方法。

public example implements BeanPostProcessor{

   //該方法的第一個參數是系統即将進行後處理的Bean執行個體,第二個參數是該Bean的配置id
   Object postProcessBeforeInitialization(Object bean, String name) throws BeansException: 
   Object postProcessAfterinitialization(Object bean, String name) throws BeansException: 
}
           

容器後處理器

容器後處理器必須實作BeanFactoryPostProcessor接口,并實作該接口的一個方法

public example implements BeanFactoryPostProcessor{ 
   postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory){}
}
           

Bean可以繼承

<bean id="parent" class=".....">
 <property name="test" value="tttt" />
</bean>

<bean id="child" class="....." parent="parent">
 <property name="test1" value="tttt" />
</bean>