装配spring bean

1.依赖注入的3种方式

  在实际环境中实现IoC容器的方式主要分为两大类,一类是依赖查找,依赖查找是通过依赖定位,把对应的资源查找回来;另一类是依赖注入,而spring主要使用的是依赖注入。一般而言,依赖注入可以分为3种方式。

  • 构造器注入

  • setter注入

  • 接口注入

  构造器注入和setter注入是主要的方式,而接口注入是从别的地方注入的方式。

1.1构造器注入

  构造器注入依赖构造方法的实现

<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进行注入。
  这样注入还是比较简单的,但是缺点也很明显,由于这里的参数比较少,所以可读性还是比较不错的,但是如果参数较多,这种构造方法就比价复杂了,这个时候就要考虑setter注入了

1.2 使用setter注入

  setter注入是spring中最主流的注入方式,利用javaBean规范所定义的setter方法来完成注入,灵活且可读性高。它是通过反射技术实现的

<bean id="departmentService" class="com.wise.tiger.service.impl.DepartmentServiceImpl" 
  init-method
="init" destroy-method="destory"> <property name="departmentName" value="生产部"/> </bean>

1.3 接口注入
    参考另一篇博文

2.装配Bean概述

  如何将Bean装配到IoC容器中,在spring中提供了三种方法进行配置

  • 在xml中显式配置

  • 在java的接口和类中实现配置

  • 隐式Bean的发现机制和自动装配原则

  在现实工作中,这三种方式都会用到,并且经常混合使用。建议优先级如下

(1)基于约定优于配置的原则,最优先的应该是隐式Bean的发现机制和自动装配原则。这样的好处是减少程序开发者的决定权,简单又不失灵活。

(2)在没有办法使用自动装配原则的情况下应该优先考虑Java接口和类中实现配置。这样的好处是避免xml配置的泛滥,也更为容易

(3)上述方法都无法使用的情况下,那么只能选择xml去配置spring IoC容器,比如第三方的类库。

  通俗来讲,当配置的类是你自身开发的工程,那么应该考虑java配置为主,而java配置又分为自动装配和Bean名称装配。在没有歧义的基础上,优先使用自动装配,这样可以减少大量的xml配置。如果所需配置的类并不是你的工程开发的,那么建议使用xml的方式。

3. 通过xml装配Bean

  引入对应的xml模式(xsd)文件

<?xml version="1.0" encoding="UTF-8"?>  
<beans xmlns="http://www.springframework.org/schema/beans"  
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
       xsi:schemaLocation="http://www.springframework.org/schema/beans  
       http://www.springframework.org/schema/beans/spring-beans.xsd">  
</beans> 
3.1.装配简易值
<bean id="departmentService" class="com.wise.tiger.service.impl.DepartmentServiceImpl">    
   <property name="departmentName" value="生产部"/>    
</bean>   
  • id:spring找到这个Bean的编号,不是一个必须的属性,如果没有指定,spring采用"全限定名#{number}的格式生成编号。

  • class:一个类的全限定名

  • property:定义类中的属性

3.2 装配集合
<bean id="personService" class="com.wise.tiger.service.impl.PersonServiceImpl">  
        <property name="personName" value="张三丰"/>  
        <property name="hobbys">  
            <array>  
                <value>看美女</value>  
                <value>看小说</value>  
                <value>看电影</value>  
            </array>  
        </property>  
        <property name="hobbyList">  
            <list>  
                <value>hobby-list-1</value>  
                <value>hobby-list-2</value>  
                <value>hobby-list-3</value>  
                <value>hobby-list-4</value>  
            </list>  
        </property>  
        <property name="hobbySet">  
            <set>  
                <value>hobby-set-1</value>  
                <value>hobby-set-2</value>  
                <value>hobby-set-3</value>  
            </set>  
        </property>  
        <property name="intro">  
            <map>  
                <entry key="name" value="peppa"/>  
                <entry key="age" value="5"/>  
                <entry key="hobby" value="我喜欢乒,我喜欢乓,我喜欢suzy和我一起跳"/>  
            </map>  
        </property>  
        <property name="prop">  
            <props>  
                <prop key="prop1">prop-value-1</prop>  
                <prop key="prop2">prop-value-2</prop>  
            </props>  
        </property>  
    </bean>  
3.3.命名空间装配
  先引入对应的命名空间和xml模式(xsd)文件
<beans xmlns="http://www.springframework.org/schema/beans"  
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
       xmlns:c="http://www.springframework.org/schema/c"  
       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 id="personService1" class="com.wise.tiger.service.impl.PersonServiceImpl"  
        p:personName="suzy"/>  
<beans/>  
       <bean id="personService2" class="com.wise.tiger.service.impl.PersonServiceImpl"  
        c:personName="suzy"/>  
<beans/>  
c:personName代表构造方法参数名为personName的参数,也可以采用c:_0表示构造方法的第一个参数
p代表引用属性,p:personName="suzy"以suzy为值,使用setPersonName方法设置。
<?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 id="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 id="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>  
通过命名空间定义set,list,map,properties等。

4.通过注解装配Bean

     更多的时候已经不再推荐使用xml的方式去装配Bean,更多的时候会考虑使用注解(annotation)的方式去装配Bean。使用注解可以减少xml的配置,注解功能更为强大,它既能实现xml的功能,也提供了自动装配的功能,程序猿所需要做的决断就减少了,更加有利于对程序的开发,这就是“约定优于配置”的开发原则。
    在Spring中,提供了两种方式来让 Spring IoC容器发现Bean。
  • 组件扫描:通过定义资源的方式,让Spring IoC容器扫描对应的包,从而把Bean装配进来。
  • 自动装配:通过注解定义,使得一些依赖关系可以通过注解完成

4.1.使用@Component装配Bean

@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

4.2.自动装配@Autowired

  通过前面Spring IoC容器的学习,我们知道spring是先完成Bean的定义和生成,然后寻找需要注入的资源。也就是当spring生成所有的bean后,如果发现这个注解,它就会在IoC容器中进行查找到对应的类型,将其注入进来,这样就完成了依赖注入。所谓自动装配是一种由spring自己发现对应的bean,自动完成装配工作的方式,它会应用到一个十分常用的注解@Autowired,这个时候spring会根据类型去寻找定义的bean然后将其注入。

  当Spring装配Bean属性时,有时候非常明确,就是需要将某个Bean的引用装配给指定属性。比如,如果我们的应用上下文中只有一个org.mybatis.spring.SqlSessionFactoryBean类型的Bean,那么任意一个依赖SqlSessionFactoryBean的其他Bean就是需要这个Bean。毕竟这里只有一个SqlSessionFactoryBean的Bean。
  为了应对这种明确的装配场景,Spring提供了自动装配(autowiring)。与其显式的装配Bean属性,为何不让Spring识别出可以自动装配的场景。
  当涉及到自动装配Bean的依赖关系时,Spring有多种处理方式。因此,Spring提供了4种自动装配策略。
<bean id="" class="" autowire="no|byName|byType|constructor|autodetect"></bean>
  • no:不进行自动装配,手动设置Bean的依赖关系
  • byName:根据Bean的名字进行自动装配
  • byType:根据Bean的类型进行自动装配
  • constructor:类似于byType,不过是应用于构造器的参数,如果正好有一个Bean与构造器的参数类型相同则可以自动装配,否则会导致错误
  • autodetect:如果有默认的构造器,则通过constructor的方式进行自动装配,否则使用byType的方式进行自动装配
  默认自动装配:在根元素Beans上增加属性default-autowire="byType"
     Spring 2.5 引入了 @Autowired 注释,它可以对类成员变量、方法及构造函数进行标注,完成自动装配的工作。 通过 @Autowired的使用来消除 set ,get方法。当 Spring 容器启动时,AutowiredAnnotationBeanPostProcessor 将扫描 Spring 容器中所有 Bean,当发现 Bean 中拥有 @Autowired 注释时就找到和其匹配(默认按类型匹配)的 Bean,并注入到对应的地方中去。IoC容器有时候会寻找失败,在默认情况下失败就会抛出异常,可以通过配置项required来改变它,比如:@Autowired(required=false)
@Service  
public class PersonServiceImpl implements PersonSerivce {  
    @Autowired  
    private PersonDao dao;  
}  

4.3.自动装配的歧义性  

  通常bean的自动装配能够给我们提供很大的方便,它会减少装配应用程序组件时所需要的显式配置的麻烦。不过,仅有一个bean匹配所需的结果时,自动装配才是有效的。如果符合条件的bean不只一个,这时就会阻碍Spring自动装配属性、构造器参数或方法参数。

  为了消除歧义性,Spring提供了两个注解@Primary和@Qualifier。

  标识首选的bean,某个接口有多个实现类,可以在某个实现类上标注@Primary,当出现歧义时,Spring会使用首选的bean,其他的会忽略,但是如果这个接口有两个实现类都标注了@Primary的话,那么又出现歧义了,所以@Primary只能标注在一个接口的一个实现类上

@Component  
@Primary  
public class PersonServiceImpl1 implements PersonService{  
  
}  
--------------------------------------------------------  
<bean id="personService1" class="com.wise.serivce.impl.PersonServiceImpl1 " primary="true" />  
--------------------------------------------------------  
@Bean  
@Primary  
public PersonService getPersonService(){  
  
    return new PersonServiceImpl1();  
}  

可以使用@Qualifier("beanName")明确指定要注入的是哪个bean

4.4.装配带有参数的构造方法类

@Service  
public class PersonServiceImpl {  
    private PersonDao dao;  
    public PersonServiceImpl(@Autowired PersonDao dao) {  
        this.dao = dao;  
    }  
}  
@Autowired和@Qualifier这两个注解可以支持到参数。
4.5.使用@Bean装配Bean
  以上大部分都是通过@Component装配Bean,但是@Component只能注解在类上,不能注解到方法上,@Bean可以注解到方法上,将方法返回的对象作为Spring的Bean存放在IoC容器中,如没指定name,bean的id默认为方法名。
@Bean  
public DataSource devDataSource(@Value("${driverClassName}") String driverClassName,  
        @Value("${url}") String url,  
        @Value("${username}") String username,  
        @Value("${password}") String password,  
        @Value("${connectionProperties}") String connectionProperties) throws Exception {  
    var prop = new Properties();  
    prop.put("driverClassName", driverClassName);  
    prop.put("url", url);  
    prop.put("username", username);  
    prop.put("password", password);  
    prop.put("connectionProperties", connectionProperties);  
    return BasicDataSourceFactory.createDataSource(prop);  
}  
  4.6.注解自定义Bean的初始化和销毁方法
@Bean(name="", initMethod="init",destroyMethod="destroy")  
@Bean的配置项中包含4个配置项。
  • name:字符串数组,允许配置多个BeanName,没有配置默认为方法名。
  • autowire:标志是否是一个引用的Bean对象,默认值是Autowire.NO
  • initMethod:自定义初始化方法
  • destroyMethod:自定义销毁方法

5.装配的混合使用
        spring-data.xml->使用xml配置数据源

<context:property-placeholder location="classpath:jdbc.properties"/>  
    <!--定义数据源:Druid数据源默认是自动提交事务,需要关闭自动提交 -->  
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">  
      <property name="driverClassName" value="${driverClassName}"/>  
      <property name="url" value="${url}"/>  
      <property name="username" value="${jdbc.username}"/>  
      <property name="password" value="${password}"/>  
      <property name="connectionProperties" value="${connectionProperties}"/>  
      <property name="defaultAutoCommit" value="${defaultAutoCommit}"/>  
</bean>  

      这种方式我们不需要去了解第三方的更多细节,也不需要过多的java代码,尤其是不用try...catch...finally...语句去处理它们,相对与@Bean的注入会更好一些,也更为简单,所以对于第三方的包或者其它外部的接口,建议使用xml的方式。
    spring同时支持这两种形式的装配,可以自由选择,无论是xml还是注解都是将bean装配到Spring IoC容器中,这样就可以通过spring IoC容器去管理各类资源了,首先使用@ImportResource,引入spring-data.xml所定义的内容。

@Configuration  
@ComponentScan(basePackages = "com.wise.tiger")  
@ImportResource(locations = {"classpath:spring-data.xml"})  
public class ApplicationConfig {  
  
}  
  当需要使用到数据源DataSource时,就可以使用@Autowired或者@Resource进行注入

6.使用Profile

  在软件开发过程中,敏捷开发模式很常见,一种时间控制的迭代式实现和发布软件的方法。那么可能是开发人员使用一套环境,而测试人员使用另外一套环境,而这两套系统的数据库是不一样的,毕竟测试人员也需要花费很多时间去构建测试数据,可不想老是被开发人员修改那些测试数据,这样就有了在不同环境中进行切换的需求了。spring也会对这样的场景进行支持。

6.1.使用@Profile配置

@Bean(name = "devDataSource")   
@Profile("dev")  
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);  
    dataSource.setAutoCommitOnReturn(defaultAutoCommit);  
    return dataSource;  
}  
@Bean(name = "testDataSource")   
@Profile("test")  
public DataSource getDataSource1(  
        @Value("${driverClassName}") String driverClassName,  
        @Value("jdbc:mysql:///test") String url,  
        @Value("${username}") String username,  
        @Value("${password}") String password) {  
    var dataSource = new BasicDataSource();  
    dataSource.setUrl(url);  
    dataSource.setUsername(username);  
    dataSource.setDriverClassName(driverClassName);  
    dataSource.setPassword(password);  
    return dataSource;  
}  
   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>  
   3.启动Profile
  当启动java配置或者xml配置profile时,Bean并不会被加载到IoC容器中。需要自行激活Profile。激活方法有5种
  • 在使用SpringMVC的情况下可以配置Web上下文参数,或者DispatchServlet参数
  • 作为JNDI条目
  • 配置环境变量
  • 配置JVM启动参数
  • 在集成测试环境中使用@ActiveProfiles

  常用激活:
  在测试代码中激活Profile,如果是开发人员进行测试,那么可以使用注解@ActiveProfiles进行定义

@RunWith(SpringJUnit4ClassRunner.class)  
@ContextConfiguration(locations="classpath:spring-profile.xml")  
@ActiveProfiles("dev")  
public class TestActiveProfile {  
} 

  在测试代码中可以加入@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>

7. 加载属性(properties)文件

  在开发过程中,配置文件往往就是那些属性(properties)文件,比如:

driverClassName = com.mysql.cj.jdbc.Driver  
url = jdbc:mysql://localhost:3306/db_book  
username = peppa  
password = pedro  
  
########## dbcp连接池基本属性 #############  
# 初始化连接  
initialSize=20  
#最大连接数量,设 0 为没有限制  
maxTotal = 0  
#最大空闲连接  
maxIdle = 10  
#最小空闲连接  
minIdle = 3  
#超时等待时间以毫秒为单位  
maxWaitMillis = 1000  
  
#JDBC驱动建立连接时附带的连接属性属性的格式必须为这样:[属性名=property;]  
#注意:"user" 与 "password" 两个属性会被明确地传递,因此这里不需要包含他们。  
connectionProperties = serverTimezone=UTC;useSSL=false;useUnicode=true;characterEncoding=utf-8  
  
#指定由连接池所创建的连接的自动提交(auto-commit)状态。如果指定为false表示关闭自动提交  
defaultAutoCommit = false  
  
#driver default 指定由连接池所创建的连接的只读(read-only)状态。默认false  
#如果没有设置该值,则“setReadOnly”方法将不被调用。(某些驱动并不支持只读模式,如:Informix)  
#defaultReadOnly=  
  
#driver default 指定由连接池所创建的连接的事务级别(TransactionIsolation)。  
#可用值为下列之一:(详情可见javadoc。)NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE  
#defaultTransactionIsolation = REPEATABLE_READ  
  使用properties是十分常见的情景,可以有效减少硬编码,有效提高运维人员的操作便利性。

7.1.使用注解方式加载属性文件

  Spring提供了@PropertySource来加载属性文件

  • name:字符串,属性配置的名称

  • value:字符串数组,可以配置多个属性文件

  • ignoreResourceNotFound:boolean值,默认值为false:如果属性文件没有找到是否忽略处理。

  • encoding:编码

@Configuration  
@ComponentScan(basePackages = "com.wise.tiger")  
@PropertySource(value = "classpath:dbcp-config.properties",ignoreResourceNotFound = true,encoding = "UTF-8")  
public class ApplicationConfig {}  
  使用注解@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);  
        dataSource.setAutoCommitOnReturn(defaultAutoCommit);  
        return dataSource;  
    }  
      
}  

   7.2.使用xml方式加载属性文件

<context:property-placeholder location="classpath:dbcp-config.properties" ignore-resource-not-fount="true"/>  
  ignore-resource-not-fount属性代表是否允许文件不存在,当默认值为false时,不允许文件不存在,如果不存在,spring会抛出异常
  location是一个配置文件路径的选项,可以配置多个或者单个文件,多个文件之间用,分割。如果系统中存在很多文件,那么属性location就要配置长长的字符串了,不过还有其它的xml方式可以进行配置:
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">  
     <!-- 字符串数组,可以配置多个属性文件-->  
     <property name="locations">  
         <array>  
            <value>classpath:jdbc.properties</value>  
            <value>classpath:message.properties</value>  
         </array>  
     </property>  
     <property name="ignoreResourceNotFount" value="true"/>  
</bean>  
8 条件化装配Bean

  在某些条件下不需要去装配Bean,比如当属性文件中没有数据源的基础配置的时候就不要去创建数据源。这时就需要通过条件化去判断。Spring提供了@Conditional去配置,通过配置一个或多个类,只是这些类需要实现接口Condition。

@Bean(name = "dataSource")   
@Conditional(DataSourceCondition.class)  
public DataSource getDataSource(  
        @Value("${driverClassName}") String driverClassName,  
        @Value("${url}") String url,  
        @Value("${username}") String username,  
        @Value("${password}") String password) {  
    var dataSource = new BasicDataSource();  
    dataSource.setUrl(url);  
    dataSource.setUsername(username);  
    dataSource.setDriverClassName(driverClassName);  
    dataSource.setPassword(password);  
    return dataSource;  
}  
  通过@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:不会创建 
     */  
    @Override  
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {  
        //获取Spring的运行环境  
        var env = context.getEnvironment();  
        //判断是否存在关于数据源的基础配置  
        return env.containsProperty("driverClassName")  
                && env.containsProperty("url")  
                && env.containsProperty("username")  
                && env.containsProperty("password");  
    }  
}  

9 Bean的作用域

  在默认情况下,Spring IoC容器只会对一个Bean创建一个实例。bean可以定义为部署在多个作用域中的一个作用域中。Spring框架支持六个作用域,其中四个作用域仅在使用Web感知的ApplicationContext时可用。还可以创建自定义范围。

singleton 单例,默认选项,在整个应用中,spring只为其生成一个Bean的实例
prototype 原型,当每次注入或者通过IoC容器获取Bean时,Spring都会为它创建一个新的实例
request 请求,web应用中使用,一次请求创建一个Bean的实例,不同的请求会创建不同的实例
session 会话,web应用中使用,会话过程中创建一个Bean的实例
application servletContext,web应用中使用,单个bean定义范围扩展到servletContext的生命周期
webscoket servletContext,web应用中使用,单个bean定义范围扩展到websocket的生命周期

  可以采用@Scope注解声明Bean的作用域
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)

10 使用SPring表达式(Spring EL)

  Spring还提供了更灵活的注入方式,那就是Spring表达式,Spring表达式语言(简称spel)是一种功能强大的表达式语言,支持在运行时查询和操作对象图。语言语法类似于统一的EL,但提供了其他特性,最显著的是方法调用和基本的字符串模板功能:

  • 使用Bean的id来引用Bean
  • 调用指定对象的方法和访问对象的属性
  • 进行运算
  • 提供正则表达式进行匹配
  • 集合配置

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

10.2 Bean的属性和方法

     使用注解的方式需要用到@Value,在属性文件的读取中使用的是$,而在spring el中则使用#。

@Component  
public class Person {  
    @Value("#{100}")  
    private Long id;  
    @Value("#{'jorge'}")  
    private String name;  
        //setters and getters  
} 
@Component  
public class ELBean {  
    @Value("#{person.id}")  
    private Long id;  
    @Value("#{'peppa'}")  
    private String name;  
      
    @Value("#{person}")  
    private Person person;  
//setters and getters  
}  
10.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;  

 

posted @ 2022-06-12 15:48  Tiger-Adan  阅读(417)  评论(0编辑  收藏  举报