国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Spring核心 Bean的高級(jí)裝配

forrest23 / 3319人閱讀

摘要:在集成測(cè)試時(shí),通常想要激活的是開發(fā)環(huán)境的。因?yàn)闆](méi)有耦合類名,因此可以隨意重構(gòu)的類名,不必?fù)?dān)心破壞自動(dòng)裝配。在裝配中,占位符的形式為使用包裝的屬性名稱。參數(shù)裝配的是名為的屬性值。

環(huán)境與profile 配置profile bean

在3.1版本中,Spring引入了bean profile的功能。使用profile,首先將所有不同的bean定義整理到一個(gè)或多個(gè)profile之中,再將應(yīng)用部署到每個(gè)環(huán)境時(shí),并確保對(duì)應(yīng)的profile處于激活(active)的狀態(tài)

在Java配置中,可以使用@Profile注解指定某個(gè)bean屬于哪一個(gè)profile。例如,在配置類中,嵌入式數(shù)據(jù)庫(kù)的DataSource可能會(huì)配置成如下所示:

從Spring 3.2開始,可在方法級(jí)別上使用@Profile注解,與@Bean注解一同使用,如下所示:

//@Profile注解基于激活的profile實(shí)現(xiàn)bean的裝配

package com.myapp;
import javax.activation.DataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
import org.springframework.jndi.JndiObjectFactoryBean;  

@Configuration
public class DataSourceConfig
{
    @Bean(destroyMethod = "shutdown")
    @Profile("dev")                                //為dev profile裝配的bean
    public DataSource embeddedDataSourece()
    {
        return new EmbeddedDataBuilder()
            .setType(EmbeddedDataSourceType.H2)
            .setScript("classpath:schema.sql")
            .setScript("classpath:test-data.sql")
            .build();
    }
    
    @Bean
    @Profile("prod")                                //為profile profile裝配的bean
    public DataSource embeddedDataSourece()
    {
        JndiObjectFactoryBean jndiObjectFactoryBean = nre JndiObjectFactoryBean();
        jndiObjectFactoryBean.setJndiName("jdbc/myDS"); 
        jndiObjectFactoryBean.setResourceRef(true); 
        jndiObjectFactoryBean.setProxyInterface(javax.sql.DataSource.class);
        return (DataSource)jndiObjectFactoryBean.getObject(); 
    }
}  

注意:盡管每個(gè)DataSource bean都被聲明在一個(gè)profile中,并且只有當(dāng)規(guī)定的profile激活時(shí),相應(yīng)的bean才會(huì)被創(chuàng)建,但可能會(huì)有其他的bean并沒(méi)有聲明在一個(gè)給定的profile范圍內(nèi)。沒(méi)有指定profile的bean始終都會(huì)被創(chuàng)建,與激活哪個(gè)profile沒(méi)有關(guān)系

在XML中配置

可以在根元素中嵌套定義元素,而不為每個(gè)環(huán)境都創(chuàng)建一個(gè)profile XML文件。這能夠?qū)⑺械膒rofile bean定義放到同一個(gè)XML文件中,如下所示:

// 重復(fù)使用元素來(lái)指定多個(gè)profile

                                //dev profile的bean 基于開發(fā)階段
    
        
        
    
    
                
                                    //qa profile的bean 基于連接池
        
    

                                    //prod profile的bean 基于生產(chǎn)環(huán)境
    
            

      

所有bean都定義到同一個(gè)XML文件之中,這種配置方式與定義在多帶帶的XML文件中的實(shí)際效果是一樣的。這里有三個(gè)bean,類型都是javax.sql.DataSource,并且ID都是dataSource。但是在運(yùn)行時(shí),只會(huì)創(chuàng)建一個(gè)bean,這取決于處于激活狀態(tài)的是哪個(gè)profile

激活profile

Spring在確定哪個(gè)profile處于激活狀態(tài)時(shí),需要依賴兩個(gè)獨(dú)立的屬性:spring.profiles.active和
spring.profiles.default

如果設(shè)置了spring.profiles.active屬性的話,那么它的值就會(huì)用來(lái)確定哪個(gè)profile是激活的。但如果沒(méi)有設(shè)置spring.profiles.active屬性的話,那Spring將會(huì)查找spring.profiles.default的值。如果spring.profiles.active和spring.profiles.default均沒(méi)有設(shè)置的話,那就沒(méi)有激活的profile,因此只會(huì)創(chuàng)建那些沒(méi)有定義在profile中的bean

設(shè)置這兩個(gè)屬性的方式:

作為DispatcherServlet的初始化參數(shù)

作為Web應(yīng)用的上下文參數(shù)

作為JNDI條目

作為環(huán)境變量

作為JVM的系統(tǒng)屬性

在集成測(cè)試類上,使用@ActiveProfiles注解設(shè)置

// 在Web應(yīng)用的web.xml文件中設(shè)置默認(rèn)的profile


    
    
        contextConfigLocation
         /WEB-INF/spring/root-context.xml 
       

                                            // 為上下文設(shè)置默認(rèn)的proflie
        spring.profiles.default
         dev 
       
    
    
        
            org.springframework.web.context.ContextLoaderListener
        
    
    
    
        appServlet
        
            org.springframework.web.servlet.DispatcherServlet
        
        
            
                spring.profiles.default
            
             dev 
        
         1 
      
    
    
        appServlet
        /
    

        
使用profile進(jìn)行測(cè)試

Spring提供了@ActiveProfiles注解,我們可以使用它來(lái)指定運(yùn)行測(cè)試時(shí)要激活哪個(gè)profile。在集成測(cè)試時(shí),通常想要激活的是開發(fā)環(huán)境的profile。如下的測(cè)試類片段展現(xiàn)了使用@ActiveProfiles激活dev profile:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {PersistenceTestConfig.class})
@ActionProfiles("dev")
public class PersistenceTest
{
    ...
}
條件化的bean

@Conditional注解,可用到帶有@Bean注解的方法上。如果給定的條件計(jì)算結(jié)果為true,就會(huì)創(chuàng)建這個(gè)bean,否則
的話,這個(gè)bean會(huì)被忽略

設(shè)有名為MagicBean的類,希望只設(shè)置magic環(huán)境屬性時(shí),Spring才會(huì)實(shí)例化這個(gè)類。如果環(huán)境中沒(méi)有這個(gè)屬性,那么MagicBean將會(huì)被忽略。在下述程序所展現(xiàn)的配置中,使用@Conditional注解條件化地配置了MagicBean:

// 條件化地配置bean
@Bean
@Conditional(MagicExistsCondition.class)                //條件化地創(chuàng)建bean
public MagicBean magicBean()
{
    return new MagicBean();
}

@Conditional給定一個(gè)Class,指明了條件——MagicExistsCondition。@Conditional將會(huì)通過(guò)Condition接口進(jìn)行條件對(duì)比:

public interface Condition
{
    boolean matches(ConditionContext ctxt, AnnotationTypeMetadata metadata)
}

設(shè)置給@Conditional的類可以是任意實(shí)現(xiàn)了Condition接口的類型。該接口實(shí)現(xiàn)簡(jiǎn)單直接,只需提供matches()方法的實(shí)現(xiàn)即可。如matches()方法返回true,那么就會(huì)創(chuàng)建帶有@Conditional注解的bean。如果matches()方法返回false,將不會(huì)創(chuàng)建這些bean

本例中,需要?jiǎng)?chuàng)建Condition的實(shí)現(xiàn)并根據(jù)環(huán)境中是否存在magic屬性來(lái)做出決策

// 在Condition中檢查是否存在magic屬性
package com.habuma.restfun;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
import org.springframework.util.ClassUtils;

public class MagicExistsCondition implements Condition
{
    public boolean matches(ConditionContext ctxt, AnnotationTypeMetadata metadata)
    {
        Environment env = context.getEnvironment();
        return env.containsProperty("magic");            // 檢查magic屬性
    }
}

ConditionContext的作用:

借助getRegistry()返回的BeanDefinitionRegistry檢查bean定義

借助getBeanFactory()返回的ConfigurableListableBeanFactory檢查bean是否存在,甚至探查bean的屬性

借助getEnvironment()返回的Environment檢查環(huán)境變量是否存在以及它的值是什么

讀取并探查getResourceLoader()返回的ResourceLoader所加載的資源

借助getClassLoader()返回的ClassLoader加載并檢查類是否存在

AnnotatedTypeMetadata能夠檢查帶有@Bean注解的方法上是否存在其他的注解及其屬性

處理自動(dòng)裝配的歧義性 標(biāo)示首選的bean

在聲明bean的時(shí)候,通過(guò)將其中一個(gè)可選的bean設(shè)置為首選(primary)bean能夠避免自動(dòng)裝配時(shí)的歧義性。當(dāng)遇到歧義性的時(shí)候,Spring將會(huì)使用首選的bean,而不是其他可選的bean

將@Component注解的IceCream bean聲明為首選的bean:

@Component
@Primary
public class IceCream implements Dessert
{
    ...
}

通過(guò)Java配置顯式地聲明IceCream,那么@Bean方法如下所示:

@Bean 
@Primary
public Dessert iceCream()
{
    return new IceCream();
}

通過(guò)XML配置bean,元素的primary屬性指定首選bean:


限定自動(dòng)裝配的bean

Spring的限定符能夠在所有可選的bean上進(jìn)行縮小范圍的操作,最終能夠達(dá)到只有一個(gè)bean滿足所規(guī)定的限制條件

@Qualifier注解是使用限定符的主要方式。它可以與@Autowired和@Inject協(xié)同使用,在注入的時(shí)候指定想要注入進(jìn)去的是哪個(gè)bean。例如,我們想要確保要將IceCream注入到setDessert()之中:

@Autowired
@Qualifier("iceCream")
public void setDessert(Dessert dessert)
{
    this.dessert = dessert;
}
創(chuàng)建自定義的限定符

bean可以設(shè)置自己的限定符,而不依賴bean ID作為限定符。在這里所需要做的就是在bean聲明上添加@Qualifier注解。例如,它可以與@Component組合使用,如下所示:

@Component
@Qualifier("cold")
public class IceCream implements Dessert{...}

在這種情況下,cold限定符分配給了IceCreambean。因?yàn)闆](méi)有耦合類名,因此可以隨意重構(gòu)IceCream的類名,不必?fù)?dān)心破壞自動(dòng)裝配。在注入的地方,只要引用cold限定符就可以了:

@Autowired
@Qualifier("cold")
public void setDessert(Dessert dessert)
{
    this.dessert = dessert;
}

通過(guò)Java配置顯式定義bean時(shí),@Qualifier可以與@Bean注解一起使用:

@beanlam[beanlam] 
@Qualifier("cold")
public Dessert iceCream()
{
    return new IceCream();
}
使用自定義的限定符注解

可以創(chuàng)建自定義的限定符注解,借助這樣的注解來(lái)表達(dá)bean所希望限定的特性。這里所需要做的就是創(chuàng)建一個(gè)注解,它本身要使用@Qualifier注解來(lái)標(biāo)注。這樣將不再使用@Qualifier("cold"),而是使用自定義的@Cold注解,該注解的定義如下所示:

@Target({ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface Cold{}

同樣可創(chuàng)建一個(gè)新的@Creamy注解來(lái)代替@Qualifier("creamy"):

@Target({ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface Creamy{}    

現(xiàn)在重新看一下IceCream,并為其添加@Cold和@Creamy注解,如下所示:

@Component
@Cold
@Creamy
public class IceCream implements Desser
{
    ...
}
bean的作用域

在默認(rèn)情況下,Spring應(yīng)用上下文中所有bean都是作為以單例(singleton)的形式創(chuàng)建的

Spring定義了多種作用域,可以基于這些作用域創(chuàng)建bean,包括:

單例(Singleton):在整個(gè)應(yīng)用中,只創(chuàng)建bean的一個(gè)實(shí)例

原型(Prototype):每次注入或者通過(guò)Spring應(yīng)用上下文獲取的時(shí)候,都會(huì)創(chuàng)建一個(gè)新的bean實(shí)例

會(huì)話(Session):在Web應(yīng)用中,為每個(gè)會(huì)話創(chuàng)建一個(gè)bean實(shí)例

請(qǐng)求(Rquest):在Web應(yīng)用中,為每個(gè)請(qǐng)求創(chuàng)建一個(gè)bean實(shí)例

單例是默認(rèn)的作用域,但是正如之前所述,對(duì)于易變的類型。如果選擇其他的作用域,要使用@Scope注解,它可以與@Component或@Bean一起使用

使用組件掃描來(lái)發(fā)現(xiàn)和聲明bean,那么在bean的類上使用@Scope注解,將其聲明為原型bean::

@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class Notepad
{
    ...
}

使用Java配置將Notepad聲明為原型bean,組合使用@Scope和@Bean來(lái)指定所需的作用域::

@Bean
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public Notepad notepad()
{
    return new Notepad();
} 

使用XML配置bean,scope屬性設(shè)置作用域:


不管使用哪種方式來(lái)聲明原型作用域,每次注入或從Spring應(yīng)用上下文中檢索該bean的時(shí)候,都會(huì)創(chuàng)建新的實(shí)例。這樣所導(dǎo)致的結(jié)果就是每次操作都能得到自己的Notepad實(shí)例

使用回話和請(qǐng)求作用域

對(duì)于購(gòu)物車bean,會(huì)話作用域最為合適,因?yàn)樗c給定的用戶關(guān)聯(lián)性最大。要指定會(huì)話作用域,可以使用@Scope注解,它的使用方式與指定原型作用域是相同的:

@Component
@Scope
{
    value = WebApplicationContext.SCOPE_SESSION,
    proxyMode = ScopedProxyMode.INTERFACES
}
public ShoppingCart cart()
{
    ...
}

將value設(shè)置成了WebApplicationContext中的SCOPE_SESSION常量(它的值是session)。Spring會(huì)為Web應(yīng)用中的每個(gè)會(huì)話創(chuàng)建一個(gè)ShoppingCart。這會(huì)創(chuàng)建多個(gè)ShoppingCart bean的實(shí)例,但是對(duì)于給定的會(huì)話只會(huì)創(chuàng)建一個(gè)實(shí)例,在當(dāng)前會(huì)話相關(guān)的操作中,這個(gè)bean實(shí)際上相當(dāng)于單例的

proxyMode屬性被設(shè)置成了ScopedProxyMode.INTERFACES。這個(gè)屬性解決了將會(huì)話或請(qǐng)求作用域的bean注入到單例bean中所遇到的問(wèn)題

若想將ShoppingCart bean注入到單例StoreService bean 的Setter方法中:

@Component
public class StoreService
{
    @Autowired
    public void setShoppingCart(ShoppingCart shoopingCart)
    {
        this.shoppingCart = shoppingCart;
    }
    ...
}

Spring并不會(huì)將實(shí)際的ShoppingCart bean注入到StoreService中,Spring會(huì)注入一個(gè)到ShoppingCart bean的代理。如下圖所示,這個(gè)代理會(huì)暴露與ShoppingCart相同的方法,所以StoreService會(huì)認(rèn)為它就是一個(gè)購(gòu)物車。但是,當(dāng)StoreService調(diào)用ShoppingCart的方法時(shí),代理會(huì)對(duì)其進(jìn)行懶解析并將調(diào)用委托給會(huì)話作用域內(nèi)真正的ShoppingCart bean

作用域代理能夠延遲注入請(qǐng)求和會(huì)話作用域的bean

如配置所示,proxyMode屬性被設(shè)置成了ScopedProxyMode.INTERFACES,這表明這個(gè)代理要實(shí)現(xiàn)ShoppingCart接口,并將調(diào)用委托給實(shí)現(xiàn)bean。如果ShoppingCart是接口,則是最理想的代理模式。但如果ShoppingCart是具體類,Spring就無(wú)法創(chuàng)建基于接口的代理。此時(shí),它必須使用CGLib來(lái)生成基于類的代理。所以,如果bean類型是具體類的話,proxyMode屬性將設(shè)置為ScopedProxyMode.TARGET_CLASS,以此來(lái)表明要以生成目標(biāo)類擴(kuò)展的方式創(chuàng)建代理

在XML中聲明作用域代理

是與@Scope注解的proxyMode屬性功能相同的Spring XML配置元素。告知Spring為bean創(chuàng)建一個(gè)作用域代理。默認(rèn)情況下,它會(huì)使用CGLib創(chuàng)建目標(biāo)類的代理。但是也可將proxy-target-class屬性設(shè)置為false,進(jìn)而要求它生成基于接口的代理:


    

使用元素,必須在XML配置中聲明Spring的aop命名空間:



運(yùn)行時(shí)值注入

避免硬編碼值,讓這些值在運(yùn)行時(shí)再確定。為了實(shí)現(xiàn)這些功能,Spring提供了兩種在運(yùn)行時(shí)求值的方式:

屬性占位符(Property placeholder)

Spring表達(dá)式語(yǔ)言(SpEL,Spring Expression Language)

注入外部的值
//使用@PropertySource注解和Environment

package soundsystem;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;  

@Configuration
@PropertySource("classpath:/com/soundsystem/app.properties")        // 聲明屬性源
public class ExpressiveConfig
{
    @Autowired
    Environment env;
    
    @Bean
    public BlankDisc disc()
    {
        return new BlankDisc(env.getProperty("disc.title"), env.getProperty("disc.artist"));        // 檢索屬性值
    }
}  

@PropertySource在上述程序中引用了類路徑中的app.properties文件,該文件如下所示:

disc.title = Sgt.Peppers Lonely Hearts Club Band;
disc.artist = Beatles;
深入學(xué)習(xí)Spring的Environment

getProperty()方法有四個(gè)重載的變種形式:

String getProperty(String key)

String getProperty(String key, String defaultValue)

T getProperty(String key, Class type)

T getProperty(String key, Class type, T defaultValue)

如果使用getProperty()方法時(shí)沒(méi)有指定默認(rèn)值,且該屬性無(wú)定義,那么獲取的值為null。如希望這個(gè)屬性必須要定義,那么可使用getRequiredProperty()方法,如下所示:

@Bean
public BlankDisc disc()
{
    return new BlankDisc(
        env.getRequiredProperty("disc.title"), env.getRequiredProperty("disc.artist")
    );
}

此時(shí),若disc.title或disc.artist屬性無(wú)定義,將會(huì)拋出IllegalStateException異常。
如想檢查一下某個(gè)屬性是否存在,可以調(diào)用Environment的containsProperty()方法:

boolean titleExists = env.containsProperty("disc.title");

將屬性解析為類使用getPropertyAsClass()方法:

Class cdClass = env.getPropertyAsClass("disc.class", CompactDisc.class);

Environment檢查profile處于激活狀態(tài)的方法:

String[] getActiveProfiles():返回激活profile名稱的數(shù)組

String[] getDefaultProfiles():返回默認(rèn)profile名稱的數(shù)組

boolean acceptsProfiles(String... profiles):如果environment支持給定profile的話,就返回true

解析屬性占位符

Spring一直支持將屬性定義到外部的屬性的文件中,并使用占位符值將其插入到Spring bean中。在Spring裝配中,占位符的形式為使用“${... }”包裝的屬性名稱。作為樣例,在XML中按照如下的方式解析BlankDisc構(gòu)造器參數(shù):

title構(gòu)造器參數(shù)所給定的值是從disc.title屬性中解析得到的。artist參數(shù)裝配的是名為disc.artist的屬性值。按照這種方式,XML配置沒(méi)有使用任何硬編碼的值,它的值是從配置文件以外的一個(gè)源中解析得到的

如果依賴于組件掃描和自動(dòng)裝配來(lái)創(chuàng)建和初始化應(yīng)用組件,那么就沒(méi)有指定占位符的配置文件或類。這種情況下,可以使用@Value注解(與@Autowired注解相似)。如在BlankDisc類中,構(gòu)造器可以改成如下所示:

public BlankDisc(
    @Value("${disc.title}")) String title,
    @Value("${disc.artist}")) String artist)
{
    this.title = title;
    this.artist = artist;
}

使用占位符必須要配置一個(gè)PropertyPlaceholderConfigurer bean或PropertySourcesPlaceholderConfigurer bean。從Spring3.1開始,推薦使用PropertySourcesPlaceholderConfigurer,因?yàn)樗軌蚧赟pring Environment及其屬性源來(lái)解析占位符

如下@Bean方法,在Java中配置了
PropertySourcesPlaceholderConfigurer:

@Beanocean[beanocean] 
public static PropertySourcesPlaceholderConfigurer placeholderConfigurer()
{
    return new PropertySourcesPlaceholderConfigurer();
}

使用XML配置,Spring context命名空間中的元素將會(huì)生成PropertySourcesPlaceholderConfigurer bean:




使用Spring表達(dá)式語(yǔ)言進(jìn)行裝配

Spring表達(dá)式語(yǔ)言(Spring Expression Language,SpEL)能夠以一種強(qiáng)大和簡(jiǎn)潔的方式將值裝配到bean屬性和構(gòu)造器參數(shù)中,在這個(gè)過(guò)程中所使用的表達(dá)式會(huì)在運(yùn)行時(shí)計(jì)算得到值

SpEL擁有很多特性,包括:

使用bean的ID來(lái)引用bean

調(diào)用方法和訪問(wèn)對(duì)象的屬性

對(duì)值進(jìn)行算術(shù)、關(guān)系和邏輯運(yùn)算

正則表達(dá)式匹配

集合操作

SpEL樣例

SpEL表達(dá)式要放到“#{ ... }”之中

#{T(System).currentTimeMillis()}

上述表達(dá)式的最終結(jié)果是計(jì)算表達(dá)式的那一刻當(dāng)前時(shí)間的毫秒數(shù)。T()表達(dá)式會(huì)將java.lang.System視為Java中對(duì)應(yīng)的類型,因此可以調(diào)用其static修飾的currentTimeMillis()方法

SpEL表達(dá)式也可以引用其他的bean或其他bean的屬性。如下表達(dá)式將計(jì)算得到ID為sgtPeppers的bean的artist屬性:

#{sgtPeppers.artist}

通過(guò)systemProperties對(duì)象引用系統(tǒng)屬性:

#{systemProperties["disc.title"]}

如通過(guò)組件掃描創(chuàng)建bean的話,在注入屬性和構(gòu)造器參數(shù)時(shí),可以使用@Value注解。如下面樣例展現(xiàn)BlankDisc從系統(tǒng)屬性中獲取專輯名稱和藝術(shù)家的名字:

public BlankDisc(
    @Value("${disc.title}")) String title,
    @Value("${disc.artist}")) String artist)
{
    this.title = title;
    this.artist = artist;
}

在XML配置中,可將SpEL表達(dá)式傳入的value屬性中,或者將其作為p-命名空間
或c-命名空間條目的值。如下BlankDisc bean的XML聲明中,構(gòu)造器參數(shù)就是通過(guò)SpEL表達(dá)式設(shè)置的:

   
表示字面值

SpEL可以用來(lái)表示整數(shù)、浮點(diǎn)數(shù)、String值以及Boolean值

引用bean、屬性的方法

SpEL所能做的另外一件基礎(chǔ)的事情就是通過(guò)ID引用其他的bean

設(shè)有一個(gè)ID為artistSelector的bean,可在SpEL表達(dá)式中按照如下的方式來(lái)調(diào)用bean的selectArtist()方法:

#{artistSelector.selectArtist()}

對(duì)于被調(diào)用方法的返回值,同樣可以調(diào)用它的方法

#{artistSelector.selectArtist().toUpperCase()}

為了避免出現(xiàn)NullPointerException,可以使用類型安全的運(yùn)算符:“?.”。這個(gè)運(yùn)算符能夠在訪問(wèn)它右邊的內(nèi)容之前,確保它所對(duì)應(yīng)的元素不是null。所以,如果selectArtist()的返回值是null的話,那么SpEL將不會(huì)調(diào)用toUpperCase()方法。表達(dá)式的返回值會(huì)是null:

#{artistSelector.selectArtist()?.toUpperCase()}    
在表達(dá)式中使用類型

如要在SpEL中訪問(wèn)類作用域的方法和常量,要依賴T()這個(gè)關(guān)鍵的運(yùn)算符。如為了在SpEL中表達(dá)Java的Math類,需要按照如下的方式使用T()運(yùn)算符:

T(java.lang.Math)

這里所示的T()運(yùn)算符的結(jié)果會(huì)是一個(gè)Class對(duì)象,代表了java.lang.Math。如果需要的話,我們甚至可以將其裝配到一個(gè)Class類型的bean屬性中。但是T()運(yùn)算符的真正價(jià)值在于它能夠訪問(wèn)目標(biāo)類型的靜態(tài)方法和常量

如需要將PI值裝配到bean屬性中:

T(java.lang.Math).PI

調(diào)用T()運(yùn)算符所得到類型的靜態(tài)方法。計(jì)算得到一個(gè)0到1之間的隨機(jī)數(shù):

T(java.lang.Math).random()
SpEL運(yùn)算符
運(yùn)算符類型 運(yùn)算符
算術(shù)運(yùn)算 +、-、*、%、^
比較運(yùn)算 <、>、==、<=、>=、lt、gt、eq、le、ge
邏輯運(yùn)算 and、or、not、
條件運(yùn)算 ?:(ternary)、?:(Elvis)
正則表達(dá)式 mathes
計(jì)算正則表達(dá)式 計(jì)算集合

SpEL中最令人驚奇的一些技巧是與集合和數(shù)組相關(guān)的

下述表達(dá)式會(huì)計(jì)算songs集合中第五個(gè)(基于零開始)元素的title屬性,這個(gè)集合來(lái)源于ID為musicBox bean:

#{musicBox.songs[4].title}

隨機(jī)選擇一首歌:

#{musicBox.songs[T(java.lang.Math).random()*timeless.songs.size()].title}   

“[]”運(yùn)算符用來(lái)從集合或數(shù)組中按照索引獲取元素,還可以從String中獲取一個(gè)字符。如下表達(dá)式引用了String中的第9個(gè)字符,也就是"G":

#{"Nothing Gonna Change My Love For You"[8]}        

SpEL提供查詢運(yùn)算符(.?[]),它會(huì)用來(lái)對(duì)集合進(jìn)行過(guò)濾,得到集合的一個(gè)子集。作為闡述的樣例,假設(shè)你希望得到musicBox中artist屬性為Khalil的所有歌曲。如下的表達(dá)式就使用查詢運(yùn)算符得到了Khalil的所有歌曲:

#{musicBox.songs.?[artist eq "Khalil"]}

SpEL還提供了另外兩個(gè)查詢運(yùn)算符:“.^[]”和“.$[]”,它們分別用來(lái)在集合中查詢第一個(gè)匹配項(xiàng)和最后一個(gè)匹配項(xiàng)。例如,考慮下面的表達(dá)式,它會(huì)查找列表中第一個(gè)artist屬性為Khalil的歌曲:

#{musicBox.songs.^[artist eq "Khalil"]}

SpEL還提供了投影運(yùn)算符(.![]),它會(huì)從集合的每個(gè)成員中選擇特定的屬性放到另外一個(gè)集合中。作為樣例,假設(shè)我們不想要歌曲對(duì)象的集合,而是所有歌曲名稱的集合。如下的表達(dá)式會(huì)將title屬性投影到一個(gè)新的String類型的集合中:

#{musicBox.songs.![title]}     

投影操作可以與其他任意的SpEL運(yùn)算符一起使用。如可使用如下表達(dá)式獲得Khalil所有歌曲的名稱列表:

#{musicBox.songs.?[artist eq "Khalil"].![title]}  
 

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/67346.html

相關(guān)文章

  • Spring - 高級(jí)裝配

    摘要:高級(jí)裝配條件化的自動(dòng)裝配與歧義性的作用域表達(dá)式語(yǔ)言環(huán)境與可以為不同的環(huán)境提供不同的數(shù)據(jù)庫(kù)配置加密算法等注解可以在類級(jí)別和方法級(jí)別,沒(méi)有指定的始終都會(huì)被創(chuàng)建的方式配置不同環(huán)境所需要的數(shù)據(jù)庫(kù)配置會(huì)搭建一個(gè)嵌入式的數(shù)據(jù)庫(kù)模式定義在測(cè)試數(shù)據(jù)通過(guò)加 高級(jí)裝配 Spring profile 條件化的bean 自動(dòng)裝配與歧義性 bean的作用域 Spring表達(dá)式語(yǔ)言 環(huán)境與profile p...

    binta 評(píng)論0 收藏0
  • Spring入門看這一篇就夠了

    摘要:甲乙交易活動(dòng)不需要雙方見面,避免了雙方的互不信任造成交易失敗的問(wèn)題。這就是的核心思想。統(tǒng)一配置,便于修改。帶參數(shù)的構(gòu)造函數(shù)創(chuàng)建對(duì)象首先,就要提供帶參數(shù)的構(gòu)造函數(shù)接下來(lái),關(guān)鍵是怎么配置文件了。 前言 前面已經(jīng)學(xué)習(xí)了Struts2和Hibernate框架了。接下來(lái)學(xué)習(xí)的是Spring框架...本博文主要是引入Spring框架... Spring介紹 Spring誕生: 創(chuàng)建Spring的...

    superw 評(píng)論0 收藏0
  • 手撕面試官系列(一):spring108道面試題合集

    摘要:解釋對(duì)象關(guān)系映射集成模塊。框架中的單例是線程安全的嗎解釋框架中的生命周期。什么是織入應(yīng)用的不同點(diǎn)解釋基于方式的切面實(shí)現(xiàn)。 前言 想必各位程序員已經(jīng)開始準(zhǔn)備金九銀十的秋招了,創(chuàng)建這個(gè)這個(gè)系列文章的目的就是為了幫助大家解決面試的問(wèn)題,系列文章將會(huì)一直更新,大家如果覺(jué)得不錯(cuò)可以關(guān)注我并轉(zhuǎn)發(fā),讓更多程序兄弟看到~接下來(lái)我們進(jìn)入正文環(huán)節(jié)(面試題+答案領(lǐng)取方式見個(gè)人主頁(yè)) 基礎(chǔ)篇 Spring 概...

    AbnerMing 評(píng)論0 收藏0
  • Spring核心 裝配Bean

    摘要:它的構(gòu)造器上添加了注解,這表明當(dāng)創(chuàng)建的時(shí)候,會(huì)通過(guò)這個(gè)構(gòu)造器來(lái)進(jìn)行實(shí)例化并且會(huì)傳入一個(gè)可設(shè)置給類型的通過(guò)自動(dòng)裝配,將一個(gè)注入到之中注解不僅能夠用在構(gòu)造器上,還能用在屬性的方法上。 Spring配置的可選方案 Spring容器負(fù)責(zé)創(chuàng)建應(yīng)用程序中的bean并通過(guò)DI來(lái)協(xié)調(diào)這些對(duì)象之間的關(guān)系。當(dāng)描述bean如何進(jìn)行裝配時(shí),Spring具有非常大的靈活性,它提供了三種主要的裝配機(jī)制: 在XM...

    wanglu1209 評(píng)論0 收藏0
  • Spring高級(jí)裝配之運(yùn)行時(shí)注入

    摘要:原文地址運(yùn)行時(shí)注入與硬編碼注入是相對(duì)的。硬編碼注入在編譯時(shí)就已經(jīng)確定了,運(yùn)行時(shí)注入則可能需要一些外部的參數(shù)來(lái)解決。提供的兩種在運(yùn)行時(shí)求值的方式屬性占位符表達(dá)式語(yǔ)言注入外部的值使用注解可以引入文件,使用其中的值。 原文地址:http://blog.gaoyuexiang.cn/Sp... 運(yùn)行時(shí)注入與硬編碼注入是相對(duì)的。硬編碼注入在編譯時(shí)就已經(jīng)確定了,運(yùn)行時(shí)注入則可能需要一些外部的參數(shù)來(lái)...

    ZweiZhao 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<