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

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配置 )。
    @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

  1. 使用构造器注入初始化bean
    2.1 注入其他bean

  

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


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

  • 直接写参数名,同上
  • 使用参数序号

  • 如果只有一个参数,可以不标示参数

2.2 注入字面量


  

使用c命名空间:


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

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


  


  
    
      xxx
      yyy
    
  


  
    
      
      
    
  


  
    
      xxx
      yyy
    
  

  1. 使用setter注入初始化bean
    使用setter注入与用构造器注入基本类似,只不过换成了和p命名空间

  
  
  
    
      xxx
      yyy
    
  

  1. 对于集合类,可以使用util命名空间创建对应的集合bean,再被引用。

  


  xxx
  yyy

1.4 混合配置

  1. JavaConfig引入JavaConfig,使用@Import注解即可
  2. JavaConfig引入XML配置,使用@ImportResource注解
  3. XML配置引入JavaConfig和XML配置


2 高级装配

2.1 profile

@Profile可以用来修饰配置类和声明Bean的方法,用value属性来指定profile。在XML配置中,使用元素的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文件中的scope属性指定作用域。

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

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

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

《Spring实战》笔记(二):装配_第1张图片
作用域代理.JPG

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

  1. 使用会话和请求作用域(通过XML)

  

表示使用作用域代理,默认创建目标类的代理,如果将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配置,则使用

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. 运算符
    《Spring实战》笔记(二):装配_第2张图片
    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实战》笔记(二):装配)