javascript
Spring注入方法
2019獨角獸企業重金招聘Python工程師標準>>>
依賴注入的3種方式
? ? 1.在xml中顯式配置
? ? 2.在java中基于注解配置
? ? 3.隱式Bean的發現機制和自動裝配原則
在現實工作中,這三種方式都會用到,并且經常混合使用。建議優先級如下?
(1)基于約定優于配置的原則,最優先的應該是隱式Bean的發現機制和自動裝配原則。這樣的好處是減少程序開發者的決定權,簡單又不失靈活。?
(2)在沒有辦法使用自動裝配原則的情況下應該優先考慮Java接口和類中實現配置。這樣的好處是避免xml配置的泛濫,也更為容易?
(3)上述方法都無法使用的情況下,那么只能選擇xml去配置spring IoC容器,比如第三方的類庫。
1.通過xml裝配
? ? ?1.1 通過setter方法配置
- id:spring找到這個Bean的編號,不是一個必須的屬性,如果沒有指定,spring采用"權限定名“(類名首字母小寫)的格式生成編號,id不支持特殊字符,且必須唯一。
- name:spring配置Bean的名稱,支持重復命名和特殊字符
- class:一個類的全限定名
- property:定義類中的屬性
? ? ?1.2 通過構造器注入
<bean id="departmentService" class="com.wise.tiger.service.impl.DepartmentServiceImpl" init-method="init" destroy-method="destory"> <!--使用類構造器實例化Bean --> <constructor-arg name="departmentName" value="生產部"/> </bean>constructor-arg用于定義類構造方法的參數,其中index用于定義參數的位置,而value則是設置值,也可以通過參數名name進行注入。
? ? ?1.3 使用命名空間注入
<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 name="user" class="com.wise.tiger.User" p:name="jack" p:age="20" p:car-ref="car"></bean> <beans/>p:name代表構造方法參數名為name的參數,也可以采用p:_0表示構造方法的第一個參數?
p:car-ref代表引用屬性
? ? ? 1.4 其他命名空間注入(如xmlns:c? ?xmlns:util)
<?xml?version="1.0"?encoding="UTF-8"?> <beans?xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation=" http://www.springframework.org/schema/beans?https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util?https://www.springframework.org/schema/util/spring-util.xsd"> <util:list?name="emails"><value>pechorin@hero.org</value><value>raskolnikov@slums.org</value><value>stavrogin@gov.org</value><value>porfiry@gov.org</value> </util:list> <util:map?id="emails"><entry?key="pechorin"?value="pechorin@hero.org"/><entry?key="raskolnikov"?value="raskolnikov@slums.org"/><entry?key="stavrogin"?value="stavrogin@gov.org"/><entry?key="porfiry"?value="porfiry@gov.org"/> </util:map> <util:set?name="emails"><value>pechorin@hero.org</value><value>raskolnikov@slums.org</value><value>stavrogin@gov.org</value><value>porfiry@gov.org</value> </util:set> <util:properties?id="jdbcConfiguration"?location="classpath:jdbc-production.properties"/> </beans>2.通過注解裝配Bean
?? 在Spring中,提供了兩種方式來讓 Spring IoC容器發現Bean。
- 組件掃描:通過定義資源的方式,讓Spring IoC容器掃描對應的包,從而把Bean裝配進來。
- 自動裝配:通過注解定義,使得一些依賴關系可以通過注解完成
? ? 2.1 使用@Component裝配Bean
? 首先打開注解掃描開關
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd "><context:component-scan base-package="cn.itcast.bean"></context:component-scan></beans>再在需要設置為Bean的類上面添加@Component注解
@Component public?class?EmilSender?{ }注解@Component代表Spring IoC容器會把這個類掃描成Bean實例。而其中的value屬性代表這個實例在Spring中的id,相當于xml方式定義的Bean的id,也可以簡寫成@Component(""),也可以直接寫成@Component,id即為類的簡單名稱首字母小寫。?
??? spring主要有四種注解可以注冊bean,每種注解可以任意使用,只是語義上有所差異:
- @Component:可以用于注冊所有bean
- @Repository:主要用于注冊dao層的bean
- @Controller:主要用于注冊控制層的bean
- @Service:主要用于注冊服務層的bean
? 2.2 自動裝配@Autowired
? ?為了應對這種明確的裝配場景,Spring提供了自動裝配。
?? 當涉及到自動裝配Bean的依賴關系時,Spring有多種處理方式。因此,Spring提供了4種自動裝配策略。?
- no:不進行自動裝配,手動設置Bean的依賴關系
- byName:根據Bean的名字進行自動裝配
- byType:根據Bean的類型進行自動裝配
- constructor:類似于byType,不過是應用于構造器的參數,如果正好有一個Bean與構造器的參數類型相同則可以自動裝配,否則會導致錯誤
- autodetect:如果有默認的構造器,則通過constructor的方式進行自動裝配,否則使用byType的方式進行自動裝配
@Autowired默認按類裝配。當 Spring 容器啟動時,AutowiredAnnotationBeanPostProcessor 將掃描 Spring 容器中所有 Bean,當發現 Bean 中擁有 @Autowired 注釋時就找到和其匹配的 Bean,并注入到對應的地方中去。IoC容器有時候會尋找失敗,在默認情況下失敗就會拋出異常,可以通過配置項required來改變它,比如:@Autowired(required=false)?
@Service public?class?PersonServiceImpl?implements?PersonSerivce?{ @Autowired(required=false) private?PersonDao?dao; }? 2.3 自動裝配@Autowired的歧義性
? ? @Autowired僅有一個bean匹配所需的結果時,自動裝配才是有效的。如果符合條件的bean不只一個,這時就會阻礙Spring自動裝配屬性、構造器參數或方法參數。?為了消除歧義性,Spring提供了兩個注解@Primary和@Qualifier。?
??? @Primary標識首選的bean,某個接口有多個實現類,可在某個實現類上標注@Primary,出現歧義時,Spring會首選該bean,忽略其他的,但@Primary只能標注在一個接口的一個實現類上
? ? ?以下三種方式:類、xml、方法使用primary
? ? 其次,可以使用@Qualifier("beanName")明確指定要注入的是哪個bean
public class BookServiceImplTest {@Autowired@Qualifier("bookService")private BookServiceImpl service; }? ?2.4?@Resource注解解決歧義(推薦使用)
@Resource(name="car")private Car car;? ? **2.5?裝配帶有參數的構造方法類**
@Service public?class?PersonServiceImpl?{private?PersonDao?dao;public?PersonServiceImpl(@Autowired?PersonDao?dao)?{this.dao?=?dao;} }? ?@Autowired和@Qualifier這兩個注解可以支持到參數。?
3. 使用@Bean裝配Bean
? ? ?以上大部分都是通過@Component裝配Bean,但是@Component只能注解在類上,不能注解到方法上,@Bean可以注解到方法上,將方法返回的對象作為Spring的Bean存放在IoC容器中,如沒指定name,bean的id默認為方法名。?
3.1 注解自定義Bean的初始化和銷毀方法
@Bean(name="",?initMethod="init",destroyMethod="destroy")@Bean的配置項中包含4個配置項。
- name:字符串數組,允許配置多個BeanName,沒有配置默認為方法名。
- autowire:標志是否是一個引用的Bean對象,默認值是Autowire.NO
- initMethod:自定義初始化方法
- destroyMethod:自定義銷毀方法
**3.2 裝配的混合使用**
??????? spring-data.xml->使用xml配置數據源?
這種方式我們不需要去了解第三方的更多細節,也不需要過多的java代碼,尤其是不用try...catch...finally...語句去處理它們,相對與@Bean的注入會更好一些,也更為簡單,所以對于第三方的包或者其它外部的接口,建議使用xml的方式。?
??? spring同時支持這兩種形式的裝配,可以自由選擇,無論是xml還是注解都是將bean裝配到Spring IoC容器中,這樣就可以通過spring IoC容器去管理各類資源了,首先使用@ImportResource,引入spring-data.xml所定義的類容。
當需要使用到數據源DataSource時,就可以使用@Autowired或者@Resource進行注入
?4.使用Profile
? ? ? 在軟件開發過程中,敏捷開發模式很常見,一種時間控制的迭代式實現和發布軟件的方法。那么可能是開發人員使用一套環境,而測試人員使用另外一套環境,而這兩天系統的數據庫是不一樣的,畢竟測試人員也需要花費很多時間去構建測試數據,可不想老是被開發人員修改那些測試數據,這樣就有了在不同環境中進行切換的需求了。spring也會對這樣的場景進行支持。?
? ? 4.1使用@Profile配置
? ? 4.2.使用xml定義Profile?
<beans?xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:jee="http://www.springframework.org/schema/jee" xsi:schemaLocation="..."> <!--?other?bean?definitions?--> <beans?profile="development"> jdbc:embedded-database?id="dataSource" jdbc:script?location="classpath:com/bank/config/sql/schema.sql"/ jdbc:script?location="classpath:com/bank/config/sql/test-data.sql"/ </jdbc:embedded-database> </beans> <beans?profile="production"> jee:jndi-lookup?id="dataSource"?jndi-name="java:comp/env/jdbc/datasource"/ </beans> </beans>? ? 4.3 啟動Profile?
? 當啟動java配置或者xml配置profile時,Bean并不會被加載到IoC容器中。需要自行激活Profile。激活方法有5種
- 在使用SpringMVC的情況下可以配置Web上下文參數,或者DispatchServlet參數
- 作為JNDI條目
- 配置環境變量
- 配置JVM啟動參數
- 在集成測試環境中使用@ActiveProfiles
常用激活:?
??? 在測試代碼中激活Profile,如果是開發人員進行測試,那么可以使用注解@ActiveProfiles進行定義
在測試代碼中可以加入@ActiveProfiles來指定加載哪個Profile,這樣程序就會自己去加載對應的profile了。但是畢竟不是什么時候都是在測試代碼中運行,有些時候要在服務器上運行,那么這個時候可以配置java虛擬機的啟動項,關于指定profile的參數存在兩個。?
spring.profiles.active?啟動的 spring.profiles.default?默認的可以配置JVM的參數來啟動對應的Profile,比如需要啟動test:
JAVA_OPTS="-Dspring.profiles.active=test"在大部分情況下需要啟動web服務器,通常可以在 web.xml 中定義全局 servlet 上下文參數 spring.profiles.default 實現,代碼如下
<!--?配置spring的默認profile?--> <context-param> <param-name>spring.profiles.default</param-name> <param-value>test</param-value> </context-param>**5 加載屬性(properties)文件**
? ? 在開發過程中,配置文件往往就是那些屬性(properties)文件,比如:?
使用properties是十分常見的情景,可以有效減少硬編碼,有效提高運維人員的操作便利性。
? ?**?5.1.使用注解方式加載屬性文件**
??? Spring提供了@PropertySource來加載屬性文件
- name:字符串,屬性配置的名稱
- value:字符串數組,可以配置多個屬性文件
- ignoreResourceNotFound:boolean值,默認值為false:如果屬性文件沒有找到是否忽略處理。
- encoding:編碼
使用注解@Value和占位符去解析屬性占位符
@Configuration @ComponentScan(basePackages?=?"com.wise.tiger") @PropertySource(value?=?"classpath:dbcp-config.properties",ignoreResourceNotFound?=?true,encoding?=?"UTF-8") public?class?ApplicationConfig?{@Value("${url}")private?String?url;@Value("${username}")private?String?username;@Value("${password}")private?String?password;@Value("${driverClassName}")private?String?driverClassName;@Value("${maxTotal}")private?int?maxTotal;@Value("${maxWaitMillis}")private?long?maxWaitMillis;@Value("${maxIdle}")private?int?maxIdle;@Value("${defaultAutoCommit}")private?boolean?defaultAutoCommit;@Value("${connectionProperties}")private?String?connectionProperties;@Bean(name?=?"dataSource")public?DataSource?getDataSource()?{var?dataSource?=?new?BasicDataSource();dataSource.setUrl(url);dataSource.setUsername(username);dataSource.setDriverClassName(driverClassName);dataSource.setPassword(password);dataSource.setMaxTotal(maxTotal);dataSource.setMaxIdle(maxIdle);dataSource.setMaxWaitMillis(maxWaitMillis);dataSource.setConnectionProperties(connectionProperties);return?dataSource;} }? ?**?5.2 使用xml方式加載屬性文件**
<context:property-placeholder?location="classpath:dbcp-config.properties"?ignore-resource-not-fount="true"/>? ? ignore-resource-not-fount屬性代表是否允許文件不存在,當默認值為false時,不允許文件不存在,如果不存在,spring會拋出異常?
??? location是一個配置文件路徑的選項,可以配置多個或者單個文件,多個文件之間用,分割。如果系統中存在很多文件,那么屬性location就要配置長長的字符串了,不過還有其它的xml方式可以進行配置:?
6 條件化裝配Bean
? ? ?在某些條件下不需要去裝配Bean,比如當屬性文件中沒有數據源的基礎配置的時候就不要去創建數據源。這時就需要通過條件化去判斷。Spring提供了@Conditional去配置,通過配置一個或多個類,只是這些類需要實現接口Condition。?
通過@Value往參數里注入了對應屬性文件的配置,但是我們沒有辦法確定這些數據源連接池的屬性是否在屬性文件中已經配置完整,如果是不充足的屬性配置,則會引起創建失敗,為此要判斷屬性文件的配置是否滿足才能繼續創建Bean。通過@Conditional去引入了一個條件判斷類----DataSourceCondition,由它來進行判斷。
package?com.wise.tiger; import?org.springframework.context.annotation.Condition; import?org.springframework.context.annotation.ConditionContext; import?org.springframework.core.type.AnnotatedTypeMetadata; /** *?條件判斷,需要實現Condition接口 */ public?class?DataSourceCondition?implements?Condition?{ /** *?判斷屬性文件中是否配置了數據源的相關參數 *?@param?context:通過它可以獲取spring的運行環境 *?@param?metadata:通過它可以獲得關于該Bean的注解信息 *?@return?true:創建對應的Bean,false:不會創建 */ @Overridepublic?boolean?matches(ConditionContext?context,?AnnotatedTypeMetadata?metadata)?{ //獲取Spring的運行環境var?env?=?context.getEnvironment(); //判斷是否存在關于數據源的基礎配置return?env.containsProperty("driverClassName")&&?env.containsProperty("url")&&?env.containsProperty("username")&&?env.containsProperty("password");}}? ?6.1 Bean的作用域
?? 在默認情況下,Spring IoC容器只會對一個Bean創建一個實例。bean可以定義為部署在多個作用域中的一個作用域中。可以采用@Scope注解聲明Bean的作用域?
7 使用SPring表達式(Spring EL)
Spring還提供了更靈活的注入方式,那就是Spring表達式,Spring表達式語言(簡稱spel)是一種功能強大的表達式語言,支持在運行時查詢和操作對象圖。語言語法類似于統一的EL,但提供了其他特性,最顯著的是方法調用和基本的字符串模板功能:
- 使用Bean的id來引用Bean
- 調用指定對象的方法和訪問對象的屬性
- 進行運算
- 提供正則表達式進行匹配
- 集合配置
? ? 7.1 Spring EL相關類
ExpressionParser?parser?=?new?SpelExpressionParser(); Expression?exp?=?parser.parseExpression("'Hello?World'"); String?message?=?(String)?exp.getValue();//The?value?of?the?message?variable?is?'Hello?World'. exp?=?parser.parseExpression("'Hello?World'.concat('!')"); message?=?(String)?exp.getValue();?//The?value?of?message?is?now?'Hello?World!'. //?Create?and?set?a?calendar GregorianCalendar?c?=?new?GregorianCalendar(); c.set(1856,?7,?9); //?The?constructor?arguments?are?name,?birthday,?and?nationality. Inventor?tesla?=?new?Inventor("Nikola?Tesla",?c.getTime(),?"Serbian"); ExpressionParser?parser?=?new?SpelExpressionParser(); Expression?exp?=?parser.parseExpression("name"); String?name?=?(String)?exp.getValue(tesla); //?name?==?"Nikola?Tesla" exp?=?parser.parseExpression("name?==?'Nikola?Tesla'"); boolean?result?=?exp.getValue(tesla,?Boolean.class); //?result?==?true? ? 7.2 Bean的屬性和方法
???? 使用注解的方式需要用到@Value,在屬性文件的讀取中使用的是$,而在spring el中則使用#。
? ? ?7.3 使用類的靜態常量和方法,運算
@Value("#{T(Math).PI}") private?double?pi; @Value("#{T(Math).random()?*?100}") private?int?random; @Value("#{person.getName()?.toString()}") private?String?note; @Value("#{person.getName()?:'peppa'}") private?String?defaultnote;?
轉載于:https://my.oschina.net/u/4134962/blog/3052922
總結
以上是生活随笔為你收集整理的Spring注入方法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: MongoDB进阶-内嵌文档查询
- 下一篇: 前端工程师必须知道的vue前端面试题目汇