1. 程式人生 > >Spring實戰筆記:Spring核心(一)

Spring實戰筆記:Spring核心(一)

spring bean

spring core


一.簡介:

1.依賴註入(DI)

優點:解耦

Spring 通過應用上下文(Application Context)裝載bean的定義,並把它們組裝起來。

Spring應用上下文負責對象的創建和組裝。

ClassPathXmlApplicationContext加載Spring上下文(ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("META-INF/spring/xxx.xml"),可通過context獲取bean)


2. 應用切面

面向切面編程(aspect-Oriented programming,AOP):可以將遍布應用各處的功能解耦出來,形成可重用的組件。關註點的分離。


3.Bean

基於Spring的應用中,,應用對象生存於Spring容器中。Spring容器負責創建對象,裝配對象,配置他們並管理他們的整個生命周期,從new到finalize()。

bean可以通過@Component("beanName")或@Named("beanName")來命名。其中@Named是Java依賴註入規範中提供的。

Spring容器不只有一個,Spring自帶了多個容器實現,可以歸為兩種不同類型:

--bean工廠:最簡單的容器,提供基本DI支持;

--應用上下文:基於BeanFactory構建,並提供應用框架級別的服務。(應用較多)

BeanFactory和FactoryBean的區別( https://www.cnblogs.com/redcool/p/6413461.html):

BeanFactory是一個工廠類,用於管理Bean的一個工廠。BeanFactory是IOC容器的核心接口,負責實例化,定位,配置應用程序中的對象及建立這些對象間的依賴。

FactoryBean是實現了FactoryBean<T>接口的Bean。根據該Bean的ID從BeanFactory中獲取的實際上是FactoryBean的getObject()返回的對象,而不是FactoryBean本身,若要獲取FactoryBean本身需要在id前面加一個&符號。

二.裝配Bean

將組件掃描得到的bean和他們的依賴裝配在一起

1.自動掃描組件

@Controller控制器:註入服務

@Service服務:註入Dao

@Repository Dao:實現Dao訪問

@Component:把普通的POJO實例化到Spring容器中,相當於配置文件中的<bean id="" class=""/>

@Controller,@Service,@Repository,@Component註解的類,並把這些類納入進Spring容器中進行管理。

引入Component的掃描組件:

其中base-package是需要掃描的包(含所有子包)

<context:component-scan base-package="com.best"/>

可以使用@Configuration替代xml配置,@ComponentScan(basePackages={"",""})指定掃描組件的包及子包下帶有@Component註解的類。@ComponentScan默認掃描所在類的包及子包。

@Controller:用於標註控制層組件

@Service:用於標註業務層組件

@Repository:用於標註數據訪問層組件,即DAO組件

@Component:泛指組件,當組件不好歸類時,可使用該註解進行標註。

@Controller,@Service,@Repository,@Component註解的類,並把這些類納入進Spring容器中進行管理。


2.自動裝配

@Autowired可以用在構造方法和類的方法上。spring會滿足方法參數上所聲明的依賴。

-- 如果沒有匹配的bean:在應用上下文創建的時候,Spring會拋出異常,為避免異常可以使用@Autowired(required=false)

-- 有匹配的bean時:若使用了@Autowired(required=false),在代碼沒有進行null檢查時,這個處於未裝配狀態的屬性可能會拋出NullPointException。

@Inject也可以完成自動裝配,是Java依賴註入規範中提供的。

三.高級裝配

@Profile("dev") -----為dev環境 profile裝配的bean

使用Profile首先要將所有不同的bean定義整理到一個活多個Profile中,在將應用部署到每個環境時,要確保對應的Profile處理激活(active)狀態,只有當規定的profile被激活時,相應的bean才會被創建。

使用@Profile註解指定某個bean屬於哪一個Profile。

激活profile方法:

-- 作為DispatcherServlet的初始化參數;

-- 作為WEB應用的上下文參數;

-- 作為JNDI條目;

-- 作為環境變量;

-- 作為JVM的系統屬性;

-- 在集成測試類上,使用@ActiveProfiles註解設置:@ActiveProfiles("dev")

@Conditional(xxxCondition.class) -----條件化地創建bean

可以用到帶有@Bean註解的方法上,如果給定條件計算結果為true,就會創建這個bean,否則這個bean將會被忽略。

設置給Conditional的類可以是任意實現了Condition接口的類型,這個接口只需提供matches()方法的實現即可。matches()方法返回true就會創建帶有 @Conditional註解的bean。

@Autowired

使用自動裝配讓Spring完全負責將bean引用註入到構造參數和屬性中,能夠減少裝配應用程序組件時所需的顯示配置的數量。

如果有多個bean能夠匹配結果時Spring會拋出NoUniqueBeanDefinitionException。

此時可以將可選bean中的某一個設為首選(@Primary,Primary與@Component或@Bean一起使用)的bean 或使用限定符(@Qualifier("xxxbeanName"),Qualifier與@Autowired一起使用)來幫助Spring將可選的bean範圍縮小到只有一個bean。

Qualifier也可以與@Component或@Bean一起使用,為某一個bean設置beanName即創建自定義的限定符,以防止bean類名修改導致找不到Qualifier指定beanName。


1.bean的作用域

默認情況下,Spring應用上下文中所有bean都是作為一單例(singleton)的形式創建的。即不管給定的一個bean被註入到其他bean多少次,每次所註入的都是同一個實例。

當所使用的類是異變的(mutable),他們會保持一些狀態,此時重用是不安全的。

Spring定義了多種作用域,可以基於這些作用域創建bean:

-- 單例(Singleton):在整個應用中,只創建bean的一個實例;

-- 原型(Prototype):每次註入或通過Spring應用上下文獲取的時候,都會創建一個bean實例;

-- 會話(Session):在Web應用中,為每個會話創建一個bean實例;

-- 請求(Request):在Web應用中,為每個請求創建一個bean實例。

單例是默認作用域,如果要選擇其他作用域,要使用@Scope註解,與@Component或@Bean一起使用:

-- 原型:@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)或@Scope("prototype")

-- 會話:@Scope(value=WebApplicationContext.SCOPE_SESSION, proxyMode=ScopedProxyMode.INTERFACES)

-- 請求:@Scope(value=WebApplicationContext.SCOPE_REQUEST, proxyMode=ScopedProxyMode.INTERFACES)

當一個會話或者請求作用域的bean(BeanSession)要註入到單例作用域的bean(BeanSingle)中時,會出現一些問題:

-- BeanSingle在Spring應用上下文加載的時候創建,此時Spring會試圖將BeanSession註入到BeanSingle中,而此時BeanSession還不存在(當有用戶進入系統,創建會話後才會被創建)。

-- 系統中可能會存在多個BeanSession,大多數情況下我們不希望註入一個固定的BeanSession到BeanSingle中,而是當前Session中的那個。

為了解決這個問題,Spring不會將實際的BeanSession註入到BeanSingle中去,而是註入一個BeanSession的代理。這個代理會暴露出和BeanSession相同的方法,BeanSingle會認為它是一個普通的BeanSession。

@Scope註解有一個proxyMode屬性,用於配置代理。有兩種方式:

-- ScopeProxyMode.INTERFACES,這表明該代理會實現BeanSession接口,並將調用 委托給具體的實現bean。這種方法要求BeanSession是一個接口。

-- ScopeProxyMode.TARGET_CLASS,這表明Spring會使用CGLib生成目標類的擴展的方式來創建代理。這種方式適用於BeanSession是具體的類。

技術分享圖片

2.運行時值註入

依賴註入通常是指將一個bean引用註入到另一個bean的屬性或構造器參數中。它通常來講是指將一個對象與另一個對象進行關聯。

依賴註入能夠將組件及其協作的其他組件解耦。

bean的裝配另一個方面是將一個值註入到bean的屬性或構造器參數中。

Spring的兩種運行時求值的方式:

-- 屬性占位符(Property placeholder):較簡單;

-- Spring表達式語言(SpEL):較強大。

占位符的形式為使用"${...}"包裝的屬性名稱,使用XML配置Spring context命名空間:

<context:property-placeholder location="classpath*:redis.properties,classpath*:shiro.properties"
ignore-unresolvable="true"/>
<!--remember Cookie-->
<bean id="rememberMeCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
<constructor-arg value="${shiro.cookie.name.prefix}-rememberMe"/>
<property name="httpOnly" value="true"/>
<property name="maxAge" value="2592000"/>
</bean>

Spring表達式語言能夠以一種強大簡潔的方式將值裝配到bean屬性和構造器參數中,在這個過程中所使用的表達式會在運行時計算得到值。

SpEL擁有如下特性:

-- 使用bean的ID來引用bean;

-- 調用方法和訪問對象的屬性;

-- 對值進行算術、關系和邏輯運算;

-- 正則表達式匹配;

-- 集合操作。

SpEL表達式要放到"#{...}"之中:

<bean id="rememberMeManager" class="org.apache.shiro.web.mgt.CookieRememberMeManager">
<!– rememberMe cookie加密的密鑰 建議每個項目都不一樣 默認AES算法 密鑰長度(128 256 512 位)–>
<property name="cipherKey" value="#{T(org.apache.shiro.codec.Base64).decode('GHxH6G3LFh8Zb3NwoRgfFA==')}"/>
<property name="cookie" ref="rememberMeCookie"/>
</bean>


Spring實戰筆記:Spring核心(一)