美文网首页
《Spring实战》笔记(二):装配

《Spring实战》笔记(二):装配

作者: JacobY | 来源:发表于2018-03-29 16:53 被阅读0次

    1 装配机制

    Spring具有非常大的灵活性,它提供了三种主要的装配机制:

    • 在XML中进行显式配置。
    • 在Java中进行显式配置。
    • 隐式的bean发现机制和自动装配。

    1.1 自动化装配

    Spring从两个角度来实现自动化装配:

    • 组件扫描(component scanning):Spring会自动发现应用上下文中所创建的bean。
    • 自动装配(autowiring):Spring自动满足bean之间的依赖。
      具体步骤如下:
    1. 用@Component注解来标记组件类。
      @Component可以设置value属性为bean的id,如果不设置,默认id为类名的首字母缩写。大多数情况下,@Named同@Component
    2. 在配置类中使用@ComponentScan注解来开启组件扫描(也可以使用xml配置 <context:component-scan>)。
      @ComponentScan默认会扫描所在类的包及其所有子包,若果要指定特定的包,可以通过value属性设置,如果要指定一个或多个包,可以使用basePackage类指定或者使用basePackageClassess来指定(指定基础包中的任一个类即可)
    3. 在要使用组件的类中使用@AutoWired注入组件。
      @AutoWired可以声明在类的属性上,也可以声明在方法上。如果没有配置的bean,Spring会抛出异常,使用@AutoWired的required属性设置为false可以避免该情况,但是被尝试注入的参数将会为null。在大多数情况下,@Inject同@AutoWired

    1.2 使用Java代码进行装配

    你想要将第三方库中的组件装配到你的应用中,在这种情况下,是没有办法在它的类上添加@Component和@Autowired注解的,因此就不能使用自动化装配的方案了。
    通过代码声明Bean,首先要创建一个方法用以返回一个实例,然后使用@Bean注解来声明。方法名为该Bean的id,也可以使用@Bean的value属性来设定Bean的id。

        @Bean
        public OneBean oneBean() {
          return new OneBean();
        }
    

    1.3 使用XML进行装配:

    1. 使用<bean>元素声明bean
    <bean id="myBean" class="myClass"/>
    
    1. 使用构造器注入初始化bean
      2.1 注入其他bean
    <bean id="myBean" class="myClass">
      <constructor-arg ref="anotherBean">
    </bean>
    

    也可以使用c命名空间,但在使用之前要在XML顶部声明其模式。

    <bean id="myBean" class="myClass" c:arg-ref="anotherBean"/>
    

    在这里,arg表示构造器参数名,有三种写法:

    • 直接写参数名,同上
    • 使用参数序号
    <bean id="myBean" class="myClass" c:_0-ref="anotherBean"/>
    
    • 如果只有一个参数,可以不标示参数
    <bean id="myBean" class="myClass" c:_-ref="anotherBean"/>
    

    2.2 注入字面量

    <bean id="myBean" class="myClass">
      <constructor-arg value="anotherBean">
    </bean>
    

    使用c命名空间:

    <bean id="myBean" class="myClass" c:arg="anotherBean"/>
    

    其他两种方式同理,和注入bean相比只是去掉了-ref

    2.3 注入集合(c命名空间不能注入集合)

    <bean id="myBean" class="myClass">
      <constructor-arg></null></constructor-arg>
    </bean>
    
    <bean id="myBean" class="myClass">
      <constructor-arg>
        <list>
          <value>xxx</value>
          <value>yyy</value>
        </list>
      </constructor-arg>
    </bean>
    
    <bean id="myBean" class="myClass">
      <constructor-arg>
        <list>
          <ref bean=bean1/>
          <ref bean=bean2/>
        </list>
      </constructor-arg>
    </bean>
    
    <bean id="myBean" class="myClass">
      <constructor-arg>
        <set>
          <value>xxx</value>
          <value>yyy</value>
        </set>
      </constructor-arg>
    </bean>
    
    1. 使用setter注入初始化bean
      使用setter注入与用构造器注入基本类似,只不过换成了<property>和p命名空间
    <bean id="myBean" class="myClass" p:literal="literal" p:pBean-ref="pBean">
      <property name="arg" ref="anotherBean"/>
      <property name="literalValue" value="value"/>
      <property name="collection">
        <list>
          <value>xxx</value>
          <value>yyy</value>
        </list>
      </property>
    </bean>
    
    1. 对于集合类,可以使用util命名空间创建对应的集合bean,再被引用。
    <bean id="myBean" class="myClass">
      <property name="arg" ref="testList"/>
    </bean>
    <util:list name="testList">
      <value>xxx</value>
      <value>yyy</value>
    </util:list>
    

    1.4 混合配置

    1. JavaConfig引入JavaConfig,使用@Import注解即可
    2. JavaConfig引入XML配置,使用@ImportResource注解
    3. XML配置引入JavaConfig和XML配置
    <bean class="JavaConfig"/>
    <import resource="abc.xml"/>
    

    2 高级装配

    2.1 profile

    @Profile可以用来修饰配置类和声明Bean的方法,用value属性来指定profile。在XML配置中,使用<beans>元素的profile属性来设置profile。激活profile是通过spring.profiles.activespring.profiles.default来确定,如果前者没有设置的话,将会查找后者,如果两者都没有设置的话,则没有激活的profile,只有没有指定profile的bean可以被创建。

    2.2 条件化配置

    @Conditional可以实现条件化地配置bean。@Conditional的value属性为一个实现了Condition接口的类,需要实现mataches()方法。@Profile本身也使用了@Conditional注解。

        @Bean
        @Conditional(DemoCondition.class)
        public DemoBean demoBean() {
            return new DemoBean();
        }
    
    public class DemoCondition implements Condition {
    
        @Override
        public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
    
            if (conditionContext.getEnvironment().containsProperty("demo")) {
                return true;
            }
            return false;
        }
    }
    

    2.3 处理自动装配的歧义

    @Primary用来修饰bean,如果在装配时发生歧义将会优先选择该Bean。@Qualifier用来指定Bean的限定符,与@AutoWired一起使用的时候,将会选择对应限定符的Bean进行装配(默认的限定符为Bean的id)。@Qualifier用来修饰Bean的时候,将会为Bean设置一个限定符。

    2.4 bean的作用域

    1. Spring定义了多种作用域,可以基于这些作用域创建bean,包括:
    • 单例(Singleton):在整个应用中,只创建bean的一个实例。在默认情况下,Spring应用上下文中所有bean都是作为以单例(singleton)的形式创建的。
    • 原型(Prototype):每次注入或者通过Spring应用上下文获取的时候,都会创建一个新的bean实例。
    • 会话(Session):在Web应用中,为每个会话创建一个bean实例。
    • 请求(Rquest):在Web应用中,为每个请求创建一个bean实例。
    1. 使用@Scope或者在xml文件中<bean>的scope属性指定作用域。

    2. 使用会话和请求作用域(通过注解)

        @Bean
        @Scope(value = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.INTERFACES)
        public DemoBean demoBean() {
            return new DemoBean();
        }
    

    要注意的是,@Scope同时还有一个proxyMode属性,它被设置成了ScopedProxyMode.INTERFACES。这个属性解决了将会话或请求作用域的bean注入到单例bean中所遇到的问题。

    作用域代理.JPG

    如果DemoBean是一个类的话,就不能使用ScopedProxyMode.INTERFACES,而要使用ScopedProxyMode.TARGET_CLASS

    1. 使用会话和请求作用域(通过XML)
    <bean id="demo" class="DemoBean" scope="session">
      <aop:scoped-proxy proxy-target-class="false"/>
    </bean>
    

    <aop:scoped-proxy/>表示使用作用域代理,默认创建目标类的代理,如果将proxy-target-class设置为false,将生成基于接口的代理

    2.5 运行时注入

    Spring提供了两种在运行时求值的方式:

    • 属性占位符(Property placeholder)。
    • Spring表达式语言(SpEL)。
    2.5.1 属性占位符

    @PropertySource可以引入其他的属性文件,并将属性加载到Spring的Environment对象中属性占位符的格式为${xxx},可以在xml文件中引用,在Java文件中,通过@Value(${xxx})注入到参数中
    在使用属性占位符之前,需要先配置一个PropertySourcesPlaceholderConfigurer bean:

    @Bean
    public static PropertySourcesPlaceholderConfigurer placeholderConfigurer() {
      return new PropertySourcesPlaceholderConfigurer();
    }
    

    如果使用xml配置,则使用 <context:property-holder/>

    2.5.2 Spring表达式语言(Spring Expression Language, SpEL)

    SpEL使用 #{...}的格式

    1. 表示字面量,直接写。String类型单双引号都可。
    #{1} 
    #{3.14} 
    #{true} 
    #{'string'} 
    #{"string"}
    
    1. 引用bean,直接引用bean id即可。链式调用的时候使用 ?. 用以避免空指针异常,如果前一个方法返回为null将不会再调用下一个方法。
    #{bean}
    #{bean.property1}
    #{bean.method1()}
    #{bean.method1().method2()}
    #{bean.method1()?.method2()}
    
    1. 访问静态方法和常量,使用T()运算符
    #{T(java.util.math).PI}
    
    1. 运算符 SpEL运算符.JPG

      条件运算中,ternary表示三元运算符。Evlis表示简化的三元运算符,用以判断空值并用默认值代替空值,如:

    #{user.name?:"no name"}
    
    1. 集合,用 [] 获取集合、数组或字符串中的元素。
    • .?[] 对集合进行查询,获取子集合
    • .^[] 获取符合条件的第一个元素
    • .$[] 获取或者条件的最后一个元素
    • .![] 对集合进行映射,如下面例子,从学生集合映射到学生名字的集合
    #{list[0]}
    #{studentList.?[age gt 16]} 
    #{studentList.^[age gt 16]}
    #{studentList.$[age gt 16]}
    #{studentList.![name]}
    

    相关文章

      网友评论

          本文标题:《Spring实战》笔记(二):装配

          本文链接:https://www.haomeiwen.com/subject/dxbmcftx.html