5.Bean
Bean的生命周期
Bean的自動裝配
Resources和ResourceLoader
5.1Bean容器的初始化
Bean容器的初始化
兩個基礎包:
org.springframework.beans
org.springframework.context
BeanFactory提供配置結構和基本功能,加載並初始化Bean
ApplicationContext保存了Bean對象並在spring中被廣泛使用
集中常用的使用場景:
常用的文件初始化方式:
FileSystemXmlApplicationContext context = new FileSystemXmlApplicationContext("F:/workspace/appcontext.xml");
ApplicationContext ac = new ClassPathXmlApplicationContext("com/xxx/spring/chap1/coll.xml");
BeanFactory factory = new ClassPathXmlApplicationContext("com/xxxspring/chap1/ioc.xml");
1.在webapp中的我們一般配置到web.xml文件中
1 <!-- 配置contextConfigLocation指定spring將要使用的配置文件 --> 2 <context-param> 3 <param-name>contextConfigLocation</param-name> 4 <param-value>classpath:action.xml,classpath:dao.xml,classpath:service.xml</param-value> 5 </context-param> 6 <!-- 配置listner讓spring讀取配置文件--> 7 <listener> 8 <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> 9 </listener>
2.load-on-startup標簽指定啟動順序,1為指在啟動服務器的時候初始化容器
1 <listener> 2 <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> 3 </listener> 4 5 <servlet> 6 <servlet-name>remoting</servlet-name> 7 <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> 8 <init-param> 9 <param-name>contextConfigLocation</param-name> 10 <param-value>classpath:spring-remoting-servlet.xml</param-value> 11 </init-param> 12 <load-on-startup>1</load-on-startup> 13 </servlet>
3Bean的兩種注入方式
a.設置值注入
b.構造注入
設置值注入案例:
基本類型的注入: 通過<property name="屬性名", value="屬性值/">為對應類對象初始化的值,這種方式必須在類中為對應的屬性提供getxxx,setxx方法
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://www.springframework.org/schema/beans 5 http://www.springframework.org/schema/beans/spring-beans-3.2.xsd"> 6 <bean name="user,user2" class="com.xxx.spring.ioc.bean.User"> 7 <property name="id" value="1"/> 8 <property name="name" value="tom"/> 9 <property name="age" value="20"/> 10 <property name="gender" value="male"/> 11 </bean> 12 </beans>
引用類型的注入:<property name="屬性名" ref="引用的bean"></property>,被引入的bean和引入處可以不在同一個xml文件中,因為所有bean都會被容器初始化並保存到容器中
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://www.springframework.org/schema/beans 5 http://www.springframework.org/schema/beans/spring-beans-3.2.xsd"> 6 <bean name="memberService" class="com.xxx.run.service.impl.IMemberServiceImpl"> 7 <property name="memberDao" ref="memberDao"></property> 8 </bean> 9 <bean name="memberDao" class="com.xxx.run.dao.impl.IMemberDaoImpl"></bean> 10 </beans>
構造注入
顧名思義,使用構造器對對象的初始化注入對應的值,實現方式有如下3種
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://www.springframework.org/schema/beans 5 http://www.springframework.org/schema/beans/spring-beans-3.2.xsd"> 6 <bean name="teacher" class="com.xxx.spring.ioc.bean.Teacher"> 7 <!-- 1.按照屬性名賦值 ,調用有參數的構造器,順序是參數順序--> 8 <constructor-arg name="id" value="1"/> <!-- person(int id,String name, String gender) --> 9 <constructor-arg name="name" value="tom"/> 10 <constructor-arg name="gender" value="male"/> 11 <!-- 2.index從0開始,按照屬性在構造器中出現的順序賦值 索引值是構造器中的屬性順序 --> 12 <!-- <constructor-arg index="0" value="2"/> 13 <constructor-arg index="1" value="jack"/> 14 <constructor-arg index="2" value="male"/> --> 15 <!-- 3.按照類型進行賦值,如果出現相同的類型,按照屬性在構造器中出現的順序進行復制 --> 16 <!--<constructor-arg type="int" value="3"/> 17 <constructor-arg type="String" value="rose"/> 18 <constructor-arg type="String" value="female"/> --> 19 </bean> 20 </beans>
Teacher.java
1 public class Teacher implements Serializable{ 2 private static final long serialVersionUID = 1L; 3 private int id; 4 private String name; 5 private String gender; 6 7 public Teacher(int id, String name, String gender) { 8 super(); 9 this.id = id; 10 this.name = name; 11 this.gender = gender; 12 } 13 14 @Override 15 public String toString() { 16 return "Teacher [id=" + id + ", name=" + name + ", gender=" + gender 17 + "]"; 18 } 19 }
測試
1 @Test 2 public void test3() throws Exception { 3 ApplicationContext ac = new ClassPathXmlApplicationContext("com/xxx/spring/chap1/constructor.xml"); 4 Teacher teacher = (Teacher) ac.getBean("teacher"); 5 System.out.println(teacher);//Teacher [id=1, name=tom, gender=male] 6 }
5.2Bean的生命周期
1 import org.springframework.beans.BeansException; 2 import org.springframework.beans.factory.BeanFactory; 3 import org.springframework.beans.factory.BeanFactoryAware; 4 import org.springframework.beans.factory.BeanNameAware; 5 6 public class Life implements BeanNameAware,BeanFactoryAware{ 7 private String name; 8 9 public Life(){//一加載就會調到用 10 System.out.println("調用無參構造器"); 11 } 12 13 public String getName() { 14 return name; 15 } 16 17 public void setName(String name) { 18 System.out.println("調用setName方法"); 19 this.name = name; 20 } 21 22 public void myInit() { 23 System.out.println("調用myInit方法"); 24 } 25 26 public void myDestory(){ 27 System.out.println("調用myDestory方法"); 28 } 29 30 @Override 31 public void setBeanFactory(BeanFactory arg0) throws BeansException { 32 System.out.println("調用setBeanFactory方法"); 33 34 } 35 36 @Override 37 public void setBeanName(String arg0) { 38 System.out.println("調用setBeanName方法"); 39 } 40 }
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xmlns:u="http://www.springframework.org/schema/util" 5 xsi:schemaLocation="http://www.springframework.org/schema/beans 6 http://www.springframework.org/schema/beans/spring-beans-3.2.xsd 7 http://www.springframework.org/schema/util 8 http://www.springframework.org/schema/util/spring-util-3.2.xsd"> 9 <!-- 調用set方法賦值后會調用myInit方法 myDestory方法最后調用--> 10 <bean name="life" class="com.xxx.spring.ioc.bean.Life" init-method="myInit" destroy-method="myDestory"> 11 <property name="name" value="tom"></property> 12 </bean> 13 </beans>
1 @Test 2 public void life(){//springBean的生命周期 3 ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("com/xxx/spring/chap2/life.xml"); 4 Life life = ac.getBean("life",Life.class); 5 System.out.println(life); 6 ac.destroy(); 7 }
調用setName方法
調用setBeanName方法
調用setBeanFactory方法
調用myInit方法
com.briup.spring.ioc.bean.Life@4f0b5b
調用myDestory方法
AfterClass 標注的方法 會最后執行
5.3Bean作用域
5.4Bean的自動裝配
this.address = address;
}
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://www.springframework.org/schema/beans 5 http://www.springframework.org/schema/beans/spring-beans-3.2.xsd"> 6 <bean name="student" class="com.xxx.spring.ioc.bean.Student" autowire="constructor"><!-- byName byType constructor(一定要提供一個單參數的構造器)--> 7 <property name="name" value="tom"/> 8 <property name="age" value="20"/> 9 <!-- <property name="address" ref="address"/> --> 10 </bean> 11 <bean name="address" class="com.briup.spring.ioc.bean.Address"> 12 <property name="country" value="中國"></property> 13 <property name="province" value="江蘇"></property> 14 <property name="city" value="蘇州"></property> 15 </bean> 16 </beans>
5.3 Aware
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://www.springframework.org/schema/beans 5 http://www.springframework.org/schema/beans/spring-beans-3.2.xsd"> 6 <bean name="applicationAawareTest" class="com.xxx.spring.aop.bean.AwareTest"></bean> 7 </beans>
1 import org.springframework.beans.BeansException; 2 import org.springframework.beans.factory.BeanNameAware; 3 import org.springframework.context.ApplicationContext; 4 import org.springframework.context.ApplicationContextAware; 5 6 public class AwareTest implements ApplicationContextAware,BeanNameAware{ 7 8 @Override 9 public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { 10 System.out.println(applicationContext.getBean(AwareTest.class)); 11 } 12 13 @Override 14 public void setBeanName(String beanName) { 15 System.out.println(beanName); 16 } 17 18 }
1 @Test 2 public void AwareTest(){ 3 ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("com/xxx/spring/chap1/aware.xml"); 4 AwareTest awareTest = ac.getBean("applicationAawareTest",AwareTest.class); 5 System.out.println(awareTest); 6 }
com.xxx.spring.aop.bean.AwareTest@1d8fe20
com.xxx.spring.aop.bean.AwareTest@1d8fe20
5.4Resource統一文件資源接口
Resources針對文件的統一接口,用於操作本地資源或網絡資源,或其他
-UrlResource:URL對應的資源,根據一個URL地址既可以構建
-ClassPathResource:獲取類路徑下的資源文件
-FileSystemResource:獲取文件系統中的資源文件
-ServletContextResource:ServletContext封裝資源,用於訪問ServletContext環境下的資源
-InputStreamResource:針對輸入流封裝的資源
-ByteArrayResource:針對字節數組封裝的資源
ResourceLoader
-所用的application context 實現了ResourceLoader接口
spring中ResourceLoader定義如下:
1 public interface ResourceLoader{ 2 Resource getResource(String location); 3 }
getResource中location的寫法有如下幾種
prefix前綴 案例 說明
classpath: classpath:com/briup/spring/chap2/life.xml 從classpath中加載
file: file:/data/life.xml用URL從文件系統中加載
http: http://myserver/logoo.png通過URL從網絡加載
(none) /spring/chap2/life.xml 這種相對路徑的寫法依賴於ApplicationContext
spring中的使用
Resource template = ctx.getResource("some/resource/path/myTemplate.txt");
Resource template = ctx.getResource("classpath:some/resource/path/myTemplate.txt");
Resource template = ctx.getResource("file:some/resource/path/myTemplate.txt");
案例:
resources.xml
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://www.springframework.org/schema/beans 5 http://www.springframework.org/schema/beans/spring-beans-3.2.xsd"> 6 <bean name="resourcetest" class="com.briup.spring.aop.bean.ResourceTest"/> 7 </beans>
ResourceTest.java
由於spring中所有的applicationcontext實現了ContextLoader接口, 所以我們實現applicationContext即有了ResourceLoader的能力
下邊:classpath:在eclipse中會加載src下的config.txt文件
1 import java.io.IOException; 2 3 import org.springframework.beans.BeansException; 4 import org.springframework.context.ApplicationContext; 5 import org.springframework.context.ApplicationContextAware; 6 import org.springframework.core.io.Resource; 7 8 9 //所有的ApplicationContext實現了ResourceLoader接口 10 public class ResourceTest implements ApplicationContextAware{ 11 12 private ApplicationContext ApplicationContext; 13 14 @Override 15 public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { 16 this.ApplicationContext = applicationContext; 17 } 18 19 public void resource() throws IOException{ 20 //Resource resource = ApplicationContext.getResource("config.txt");//默認為classpath 21 //Resource resource = ApplicationContext.getResource("classpath:config.txt"); 22 //Resource resource = ApplicationContext.getResource("file:D:\\workspace\\xnxy_spring\\src\\config.txt"); 23 Resource resource = ApplicationContext.getResource("url:http://repo.springsource.org/libs-release-local/org/springframework/spring/3.2.4.RELEASE/spring-framework-3.2.4.RELEASE-dist.zip"); 24 System.out.println(resource.getFilename());//獲取文件名 25 System.out.println(resource.contentLength()); //獲取文件長度 26 System.out.println(resource.getInputStream());//獲取輸入流 27 } 28 }
測試:
1 @Test 2 public void ResourceTest(){ 3 ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("com/briup/spring/chap1/resources.xml"); 4 ResourceTest resourceTest = ac.getBean("resourcetest",ResourceTest.class); 5 try { 6 resourceTest.resource(); 7 } catch (IOException e) { 8 e.printStackTrace(); 9 } 10 }
6.Bean容器的注解實現
Classpath掃描與組件管理
類的自動檢測與注冊Bean
<context:annotation-config/>
@Component, @Repository, @Service, @Constroller
@Required
@Autowired
@Qualifier
@Resource
6.1classpath掃描與組件管理
@Configuration, @Bean, @Import, @DependsOn
@Component是Spring中的一個通用注解,可以用於任何Bean,相當於注解的超類,如果不知道位於那個層,一般使用該注解
@Repository, @Service, @Controller是更具有針對性的注解
- @Repository,通常用於注解DAO,即持久層的注解
- @Service,通常用於追注解Service類,即服務層
- @Controller通常用於注解Controller,即控制層(MVC)
6.2類的自動檢測與注冊Bean
1 <context:component-scan base-package="spring.aop.bean.annotation"></context:component-scan>
1 <!--默認情況下,spring中自動發現並被注冊bean的條件是: 2 使用@Component, @Repository, @Service, @Constroller其中之一的注解 3 或者使用基於@Component的自定義注解 4 5 可以通過過濾器修改上邊的行為,如下邊的例子XML配置忽略所有@Repository注解並用“stub”代替 6 --> 7 8 9 <context:component-scan base-package="spring.aop.bean.annotation"> 10 <!-- 通過include-filter包含注解,exclude-filter排除注解 --> 11 <context:include-filter type="regex" expression=".*Stub.*Repository"/> 12 <!-- 排除@Repository注解 --> 13 <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository"/> 14 </context:component-scan>
6.3使用注解管理bean
都會有個name屬性用於顯示設置BeanName)
//顯示設置beanName,相當於在xml配置bean的是id的值
@Service("myMoveLister")
public class simpleLlister{
//..
}
Dao
//設置beanName默認使用類名,首字母小寫作為beanName
@Repository
public class MovieFinderImpl implements MovieFinder{
}
6.3.1 作用域scope
作用域的注解Scope
通常情況下自動查找的Spring組件,其Scope是singleton,其Spring2.5提供了Scope的注解 @Scope
@Scope("prototype") //括號中指定Scope的范圍,默認
@Repository
public class MovieFinderImpl implements MovieFinder{
}
也可以自定義scope策略,實現ScopeMetadataResolver接口並提供一無參數的構造器
<context:component-scan base-package="spring.aop.bean.MyScopeResolver"></context:component-scan>
6.3.2注解的具體案例使用
//由於不知道其作用於DAO或Service所以使用通用注解,如果知道具體作用在那層,我們一班使用更具體注解方式如@Service,@Repository等
1 //@Component -->默認使用類名小寫作為bean的name 2 @Scope("prototype") //括號中為Scope的范圍,這里設置為原型模式 3 @Component("beanAnnotation") 4 public class BeanAnnotation { 5 6 public void say(String arg){ 7 System.out.println("BeanAnnotation: "+arg); 8 } 9 }
測試:
1 @Test 2 public void testAnnotation(){ 3 ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("com/xxx/spring/chap4/annotation.xml"); 4 //@Component沒有value值的話,默認使用類名首字母小寫作為bean的id,指定value以value值為准作為id 5 BeanAnnotation beanAnnotation1 = ac.getBean("beanAnnotation",BeanAnnotation.class); 6 BeanAnnotation beanAnnotation2 = ac.getBean("beanAnnotation",BeanAnnotation.class); 7 System.out.println(beanAnnotation1); 8 System.out.println(beanAnnotation2); 9 //結果 10 //com.xxx.spring.aop.bean.annotation.BeanAnnotation@1598d5f 11 //com.xxx.spring.aop.bean.annotation.BeanAnnotation@505fd8 12 }
6.3.3一個不常用的注解@Required
這個注解僅僅標識,受影響的bean屬性必須在配置時被填充,通過bean定義或通過自動裝配一個明確的屬性值
private MoiveFinder movieFinder;
@Required
public void setMovieFinder(MovieFinder movieFinder){
this.movieFinder = movieFinder;
}
//..
}
6.3.4@Autowired
這個注解相當於我們之前在xml文件中配置的autowire="constructor/byName/byType",只不過我們這里使用@Autowired方式注解方式,且默認是通過類型判斷,意思就是不使用byName,和construtor。通過@Autowired注解,spring會自動去容器中查找對應的類型,注入到該屬性中,且bean類中,使用@Autowired注解其屬性,我們可以不用提供getter,setter方法
使用@Autowired
@Autowried對屬性進行注解的時候,我們可以省略getter,setter方法,通過對應的bean的類型,對屬性值注入
@Autowried對seter方法進行注解的時候,可以注入對應的值
@Autowried對構造器進行注解的時候,可以通過類型找到對應的bean注入
@Autowried可以將 @Autowried為”傳統“的setter方法代替 @Required
@Autowried自動注入,會去容器中按照類型查找對應的bean注入
案例:
setter中使用
1 pulic class simpleMovieLister{ 2 3 private MoiveFinder movieFinder; 4 5 @Autowried 6 public void setMovieFinder(MovieFinder movieFinder){ 7 this.movieFinder = movieFinder; 8 } 9 //.. 10 }
屬性和構造器中使用
1 pulic class MovieRreCommender{ 2 3 成員變量中 4 @Autowried 5 private MovieCatalog movieCatalog; 6 7 private CustomerPreferenceDao customerPreferenceDao; 8 9 //構造器中 10 @Autowried 11 public MovieRreCommender(CustomerPreferenceDao customerPreferenceDao){ 12 this.CustomerPreferenceDao = CustomerPreferenceDao; 13 } 14 }
上邊的seter方式,構造器方式,屬性方式,效果都是一樣的,使用其中任何一種,都可以實現注入。不過由於,@Autowired是通過類型判斷是否注入到使用該注解地方,假如容器中出現兩個以上的相同類型的bean實例,就會報錯,這時我們就必須指定注入那個id名的bean實例,主要有兩種方法解決該問題:
@Autowired(requried=false), @Qualifie("beanName)指定@Autowired注入那個bean實例
6.3.5@Autowried(requried=false)
默認情況下,如果因找不到合適的bean將會導致autowiring失敗拋出異常,可以通過下邊
這種方式避免
pulic class simpleMovieLister{
private MoiveFinder movieFinder;
@Autowried(requried=false)//指明該屬性不是必須的,找不到的情況下不會拋出異常
public void setMovieFinder(MovieFinder movieFinder){
this.movieFinder = movieFinder;
}
//..
}
提示:每一類中只能有一個構造器被標記為requried=ture建議將 @Autowired的必要屬性時,使用 @Requried注解
6.3.6@Qualifier--配合 @Autowired
注解縮小注解范圍(或指定唯一),也可以用於指定單獨的構造參數的方法參數
可以適用於注解集合類型的變量
案例:
1 public class MovieRecommander{ 2 @Autowired 3 @Qualifier("beanName") 4 private MovieCatalog movieCatalog; 5 6 private CustomerPreferenceDao customerPreferenceDao; 7 //@Qualifier也可以實現參數的注入 8 public void prepare(@Qualifier("beanName")CustomerPreferenceDao customerPreferenceDao){ 9 this.customerPreferenceDao = customerPreferenceDao; 10 } 11 }
指定一個bean的id注入到該屬性中,可以在方法的參數中使用
6.3.7@Autowired注解可以方便的注解那些眾所周知的解析依賴性接口
比如說:BeanFacotry,ApplicationContext,Environment,ResourceLoader,ApplicaiontEventPublisher, MessageSource等
1 pulic class simpleMovieLister{ 2 3 @Autowired 4 private AplicationContext context; 5 6 public simpleMovieLister(){} 7 8 }
上邊的案例使用autowired注解ApplicationContext,這樣我們就可以活ApplicatioinContext容器總的bean對象
6.3.8@Autowired將容器中相關類型的bean注入到一個集合或數組中
1 public interface BeanInterface { 2 3 4 }
1 @Order(1) 2 @Component 3 public class BeanImplOne implements BeanInterface { 4 5 }
1 @Order(2) //Order排序注解只對list,或數組集合有效括號里邊是排序順序 2 @Component 3 public class BeanImplTwo implements BeanInterface { 4 5 }
1 import java.util.List; 2 import java.util.Map; 3 import java.util.Map.Entry; 4 import java.util.Set; 5 import org.springframework.beans.factory.annotation.Autowired; 6 import org.springframework.stereotype.Component; 7 8 @Component 9 public class BeanInvoker { 10 11 @Autowired //該注解會將所有的BeanInterface類型的bean注入到該list中 12 //如果bean有 @Order注解可以實現排序 13 private List<BeanInterface> list; 14 15 //該注解會將所有的BeanInterface類型的bean注入到該map中,key值為bean的名字 16 //是String類型,map類型無排序可言 17 @Autowired 18 private Map<String, BeanInterface> map; 19 20 public void print(){ 21 if(list != null && 0 != list.size()){ 22 System.out.println("list..."); 23 for(BeanInterface beanInterface:list){ 24 System.out.println(beanInterface.getClass().getName()); 25 } 26 } 27 if(map != null && 0 != map.size()){ 28 System.out.println("map..."); 29 Set<Entry<String, BeanInterface>> entrySet = map.entrySet(); 30 for(Entry<String, BeanInterface> entry: entrySet){ 31 System.out.println(entry.getKey()+"--"+entry.getValue().getClass().getName()); 32 } 33 } 34 } 35 }
1 @Test 2 public void testAutowired2(){ 3 ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("com/xxx/spring/chap4/annotation.xml"); 4 BeanInvoker beanInvoker = (BeanInvoker) ac.getBean("beanInvoker"); 5 beanInvoker.print(); 6 }
結果:
com.xxx.spring.aop.bean.annotation.BeanImplOne
com.xxx.spring.aop.bean.annotation.BeanImplTwo
map...
beanImplOne--com.xxx.spring.aop.bean.annotation.BeanImplOne
beanImplTwo--com.xxx.spring.aop.bean.annotation.BeanImplTwo
6.4@Bean注解的使用
1 @Configuration //相當於配置文件 2 public class Appconfig{ 3 4 @Bean("myservice")//假如bean的name屬性沒有指定名字的話,注入的是id為方法名的bean,一般我們指定name屬性不容易出錯 5 public Myservice myservice(){ 6 return new MyServiceImpl(); 7 } 8 /* 9 對比基於XML文件中的配置效果類似 10 <bean id="myservice" class="com.xxx.service.MyserviceImpl"></bean> 11 */ 12 }
1 <bean name="life" class="com.briup.spring.ioc.bean.Life" init-method="myInit" destroy-method="myDestory"> 2 <property name="name" value="tom"></property> 3 </bean>
1 public class Foo{ 2 public void init(){ 3 4 } 5 } 6 7 public class Bar{ 8 public void cleanup(){ 9 10 } 11 }
1 @Configuration 2 public class Appconfig{ 3 4 @Bean(name="life") //定義bean的name 5 public Life life(){ 6 return new Life(); 7 } 8 9 @Bean(initMethod="init") //在初始化Foo的時候,會調用Foo.java中的init方法 10 public Foo foo(){ 11 return new Foo(); 12 } 13 14 @Bean(destoryMethod=“cleanup”) //在銷毀Bar的時候會調用Bar.java中的cleanup中的方法 15 public Bar bar(){ 16 return new Bar(); 17 } 18 }
6.5使用注解模擬連接數據庫
jdbc.url=jdbc:oracle:thin:@localhost:1521:XE
jdbc.username=caojx
jdbc.password=caojx
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:context="http://www.springframework.org/schema/context" 4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 5 xsi:schemaLocation="http://www.springframework.org/schema/beans 6 http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 7 http://www.springframework.org/schema/context 8 http://www.springframework.org/schema/context/spring-context.xsd" > 9 <!-- 加載db.properties文件 --> 10 <context:property-placeholder location="classpath:db.properties"/> 11 <!--context:component-scan包含context:annotation-config的全部功能,通常使用前者后,不再使用后者 12 <context:component-scan base-package="com.briup.spring.aop.bean.annotation"></context:component-scan> 13 14 </beans>
1 public class MyDriverManager { 2 3 public MyDriverManager(String url, String userName, String password){ 4 System.out.println("url :"+url); 5 System.out.println("userName :"+userName); 6 System.out.println("password :"+password); 7 } 8 9 }
1 @Configuration 2 @ImportResource("classpath:com/xxx/spring/chap4/config.xml") //指定配置文件的路徑 3 public class MyConnection { 4 5 6 @Value("${jdbc.url}") //基本類型的變量使用@Value注解(括號里邊是注入的值) ,這是使用${是讀取配db.properties中的值} 7 private String url; 8 9 @Value("${jdbc.username}") //如果db.properties中寫法為username默認取的是當前操作系統用戶的名稱,可以在db.properties定義username的時候使用jdbc.username 10 private String userName; 11 12 @Value("${jdbc.password}") 13 private String password; 14 15 @Bean(name="myDriverManager") 16 17 public MyDriverManager MyDriverManager(){ 18 return new MyDriverManager(url,userName,password); 19 } 20 21 }
ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("com/xxx/spring/chap4/annotation.xml");
System.out.println(ac.getBean("myDriverManager"));
結果:
url :jdbc:oracle:thin:@localhost:1521:XE
userName :caojx
password :caojx
com.briup.spring.aop.bean.annotation.MyDriverManager@152b54b
同時:@Bean注解也可以配置@Scope使用
1 @Bean(name="myDriverManager") 2 @Scope("prototype") 3 public MyDriverManager MyDriverManager(){ 4 return new MyDriverManager(url,userName,password); 5 } 6 7 @Bean(name="myDriverManager") 8 @Scope("singleton") 9 public MyDriverManager MyDriverManager(){ 10 return new MyDriverManager(url,userName,password); 11 }
提示:spring配置數據庫連接,或事務管理這一塊,將會專門使用一篇來說明。
6.6Spring對JSR的注解支持
JSR常見的注解有如下
@Resource等效於@Autowired與@Inject
@PostConstrct 初始化回掉
@PreDetory 銷毀回調用
@Inject 等效於 @Autowired
@Named 與 @Compenet等效
6.6.1@Resource
而@Resource默認按 byName自動注入罷了。
@Resource有兩個屬性是比較重要的,分是name和type,
Spring將@Resource注解的name屬性解析為bean的名字,而type屬性則解析為bean的類型。
所以如果使用name屬性,則使用byName的自動注入策略,而使用type屬性時則使用byType自動注入策略。如果既不指定name也不指定type屬性,這時將通過反射機制使用byName自動注入策略。
@Resource裝配順序
1. 如果同時指定了name和type,則從Spring上下文中找到唯一匹配的bean進行裝配,找不到則拋出異常
2. 如果指定了name,則從上下文中查找名稱(id)匹配的bean進行裝配,找不到則拋出異常
3. 如果指定了type,則從上下文中找到類型匹配的唯一bean進行裝配,找不到或者找到多個,都會拋出異常
4. 如果既沒有指定name,又沒有指定type,則自動按照byName方式進行裝配;如果沒有匹配,則回退為一個原始類型進行匹配,如果匹配則自動裝配;
5. 如果 @Resource用於方法中,默認使用方法名作為beanName,指定名字則使用名字
案例:
DAO
1 import org.springframework.stereotype.Repository; 2 3 @Repository 4 public class JsrDAO { 5 6 public void save(){ 7 System.out.println("JsrDao invoker"); 8 } 9 10 }
Service
1 import javax.annotation.PostConstruct; 2 import javax.annotation.PreDestroy; 3 import javax.annotation.Resource; 4 5 import org.springframework.stereotype.Service; 6 7 import com.briup.spring.aop.bean.annotation.dao.JsrDAO; 8 9 @Service 10 public class JsrService { 11 12 @Resource 13 private JsrDAO jsrDAO; 14 15 @Resource //作用與上邊一樣,二選一都可以 16 public void setJsrDAO(JsrDAO jsrDAO){ 17 this.jsrDAO = jsrDAO; 18 } 19 20 public void save(){ 21 jsrDAO.save(); 22 } 23 24 @PostConstruct 25 public void init(){ 26 System.out.println("jsr Service init"); 27 } 28 29 @PreDestroy 30 public void destory(){ 31 System.out.println("jsr Service destory"); 32 } 33 34 }
提示:
@Resource的處理是由ApplicationContext中的CommonAnnotationBeanPostProecssor發現並處理的
CommonAnnotationBeanPostProecssor不僅支持 @Resource注解,還支持 @PostConstruct初始回調
和 @PreDestory銷毀回調,前提是CommonAnnotationBeanPostProecssor是在ApplicationContext中注冊的
測試結果:
@Test
public void testJsr(){
ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("com/briup/spring/chap4/annotation.xml");
System.out.println(ac.getBean("jsrService"));
ac.destroy();
}
結果:
jsr Service init
com.briup.spring.aop.bean.annotation.service.JsrService@7dc4cb
jsr Service destory
@Resource是一個比比較常用的JSR注解,對於JSR中的其他注解,這里不進行詳細的介紹。