天天看點

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

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:泛指元件,當元件不好歸類時,可使用該注解進行标注。

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是具體的類。

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

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;

        -- 調用方法和通路對象的屬性;

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

        -- 正規表達式比對;

<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>