https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans

1 概览总结

1.1 核心实现包:

  • org.springframework.beans

  • org.springframework.context

1.2 核心对象:

  • BeanFactory

  • ApplicationContext

2 容器

Spring 容器里面的对象,都称之为Bean,同一由容器创建、分配、管理。

可以通过创建`ClassPathXmlApplicationContext` 或 FileSystemXmlApplicationContext 来创建容器。提供一些xml配置信息。不常用,在 测试中看到使用过,创建容器,获取bean对象。

2.1 元信息

元信息,用于创建bean对象。元信息可以通过三种方式定义:

  • xml 最原始的方式,所有bean均可通过xml定义

  • 注解:例如@Service @Component,这些注解的类,会被创建bean对象

  • java 配置。可以再java类中进行bean对象,配置。结合 @Configuration, @Bean,等等对象。

2.2 创建容器

ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");

xml均为需要配置的对象文件。应用场景不广,不做深入研究。

2.3 使用容器

容器,实质就是bean对象的一个集合,可以从容器中获取想要的bean对象,bean默认是单例。

// 创建容器
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");

// 获取对象
PetStoreService service = context.getBean("petStore", PetStoreService.class);

// 使用对象方法
List<String> userList = service.getUsernameList();

2.4 Bean 对象

2.4.1 bean 命名

bean 对象可以有多个名称,但是必须全局唯一。可以通过xml通过id或者name属性设置。注解也可设置name属性,如果不设置,默认类名小写开头,驼峰。accountManager, accountService, userDao, loginController 等等。

可以设置别名,等效,但是一般没用到过。

2.5 初始化 bean 的多种方式

看了一遍,没啥感觉。

3 依赖

构造器注入,以及set注入,结合xml中属性进行对象配置。不太实用了。现在都是注解。

4 bean 的scopes

  • singleton 在IOC容器中只存在一个实例,也就是通过singleton作用域创建的对象是单例的。

  • prototype 第次从IOC容器中获取对象时,都返回一个新对象。

  • request 每次HTTP请求都会创建一个新的对象,当请求结束时则会自动销毁这个对象。该作用域只针对Web环境中使用。

  • session 同一个HTTP Session共享一个对象,不同的HTTP Session使用不同的对象,当这个Session结束时销毁这个对象。该作用域也是只针对Web环境中使用的。

  • globalSession 同一个全局Session共享一个对象,该作用域也是只针对Web环境中使用的。

注:还可以自定义作用范围。

5 自定义 bean nature

  • bean 生命周期,各种回调。

  • ApplicationContextAware and BeanNameAware

  • 其他 Aware 接口

5.1 生命周期回调

方式: - 实现 InitializingBean 、DisposableBean ,实现方法,从而实现bean初始化、销毁时回调函数。 - 使用JSRO-250 @PostConstruct @PreDestroy 注解,在bean对象创建前,销毁后执行。

5.1.1 初始化回调

  • 实现 InitializingBean ,并实现 afterPropertiesSet 方法,即可

  • 使用注解 @PostConstruct 标注初始化方法。

  • 使用 init-method 属性(xml中), initMethod 属性(@Bean)

5.1.2 销毁时回调

  • 实现 DisposableBean 接口

  • 使用 @PreDestroy 标注方法

  • 使用 destroy-method 属性(xml中), destroyMethod 属性(@Bean)

5.2 启动 和 关闭 回调

有些特殊场景,一些对象有自己独特的生命周期需要,可以设置启动或者关闭时回调。核心接口 Lifecycle

5.3 非web应用,关闭 IOC 容器时回调

5.4 Aware

感知、意识到。使用Aware,将与Spring耦合。 https://my.oschina.net/u/4149877/blog/3076044

6 Bean 定义继承

Bean,如果继承父类,父类bean的属性可以被子类bean继承。

7 容器扩展方法

忽略

8 基于注解的容器配置

8.1 @Required

Spring 5.1 开始弃用此注解。此注解作用为,标注在配置期间,bean的属性必须存在。严格意义上检查,避免空指针。

8.2 @Autowired

JSR 330 @Inject 作用相同。

  • 作用于构造器上,注入对象

  • 作用于 setter 上,注入对象

  • 作用于 方法上,注入对象

  • 作用于 对象上

  • 可混合使用

此外还有一个注解 @Resource, 此注解也能注入对象,但是有局限性,只支持 filed 以及setter方法,且只能有一个参数。

非必须:注入对象时,不一定需要此对象存在。

  • @Autowired(required = false)

  • Optional

  • @Nullable

通过 @Order 或者 @Priority 注解,可以设置优先级。不使用注解,可以通过实现接口 org.springframework.core.Ordered

8.3 @Primary

注入对象的时候,默认是根据类型注入的,这时候可以指定优先级,则在注入的时候,优先注入级别高的。

8.4 @Qualifier

使用此注解, 可以指定注入命名的bean。在生成需要依赖的Bean对象时。

自定义 qualifier 注解。

@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface Genre {
    String value();
}

然后就可以用 @Genre 代替 @Qualifier。

8.5 @Value

  • 一般用于注入属性值

  • 使用 EL 表达式,生成所需属性

9 classpath 扫描以及管理 components

9.1 常见注解

@Repository, @Component, @Service, and @Controller

根据业务功能选择合适的注解进行标注,如如controller层选用@Controller。尤其需要注意的是@Component,这个可以用来标识Bean,但非service层的。

9.2 元注解和组合注解

spring 提供的注解大多是元注解,可以组合其他注解,将功能进行结合。

例如 @RestController 包含@Controller and @ResponseBody,可以实现2个注解的作用。

@Scope(WebApplicationContext.SCOPE_SESSION)

@SessionScope

9.3 扫描

@Configuration
@ComponentScan(basePackages = "org.example")
public class AppConfig  {
   // ...
}

org.example 包下使用注解标注的Bean对象,创建、管理。

9.5 使用compoent 定义 Bean 的元信息

@Component
public class FactoryMethodComponent {

    @Bean @Scope("prototype")
    public TestBean prototypeInstance(InjectionPoint injectionPoint) {
        return new TestBean("prototypeInstance for " + injectionPoint.getMember());
    }
}

@Component 标注类。多个注解标注生成的Bean对象。

9.6 Bean 命名

在定义Bean时,可以手动指定名称,也可以不指定,使用默认的bean name 生成策略(类名首字母小写,驼峰)。当然也可以自定义。

实现 BeanNameGenerator 接口。生成Bean对象时,指明name生成策略

@Configuration
@ComponentScan(basePackages = "org.example", nameGenerator = MyNameGenerator.class)
public class AppConfig {
    // ...
}

9.7 使用 scope 指定 自动检测 components

使用 @Scope,默认是 singleton, 可以通过注解指定范围。也可以自定义范围解析类。

实现 ScopeMetadataResolver 接口

指定范围解析。

@Configuration
@ComponentScan(basePackages = "org.example", scopeResolver = MyScopeResolver.class)
public class AppConfig {
    // ...
}

还可以限制范围代理类型

@Configuration
@ComponentScan(basePackages = "org.example", scopedProxy = ScopedProxyMode.INTERFACES)
public class AppConfig {
    // ...
}

scopedProxy: no, interfaces, and targetClass

10 使用 JSR 330 标准注解。

需要加入jar

<dependency>
    <groupId>javax.inject</groupId>
    <artifactId>javax.inject</artifactId>
    <version>1</version>
</dependency>

其实就是spring 相关注解的另一种同等作用注解。

Spring javax.inject.* javax.inject restrictions / comments

@Autowired

@Inject

@Inject has no ‘required’ attribute. Can be used with Java 8’s Optional instead.

@Component

@Named / @ManagedBean

JSR-330 does not provide a composable model, only a way to identify named components.

@Scope(“singleton”)

@Singleton

The JSR-330 default scope is like Spring’s prototype. However, in order to keep it consistent with Spring’s general defaults, a JSR-330 bean declared in the Spring container is a singleton by default. In order to use a scope other than singleton, you should use Spring’s @Scope annotation. javax.inject also provides a @Scope annotation. Nevertheless, this one is only intended to be used for creating your own annotations.

@Qualifier

@Qualifier / @Named

javax.inject.Qualifier is just a meta-annotation for building custom qualifiers. Concrete String qualifiers (like Spring’s @Qualifier with a value) can be associated through javax.inject.Named.

@Value

-

no equivalent

@Required

-

no equivalent

@Lazy

-

no equivalent

ObjectFactory

Provider

javax.inject.Provider is a direct alternative to Spring’s ObjectFactory, only with a shorter get() method name. It can also be used in combination with Spring’s @Autowired or with non-annotated constructors and setter methods.

了解即可。还是使用spring。

11 基于java代码,进行容器配置

主要是关于 @Comfiguration 以及 @Bean

  • @Configuration 重量级选手,在其配置内,可以解决依赖问题。

  • @Bean 轻量级,结合component注解,也能生成bean对象,但是如果内部复杂,有其他依赖,则无法实现。只使用于简单的bean对象生成。

11.1 @Import

@Configuration
public class ConfigA {

    @Bean
    public A a() {
        return new A();
    }
}

@Configuration
@Import(ConfigA.class)
public class ConfigB {

    @Bean
    public B b() {
        return new B();
    }
}

通过import,生成ConfigB中的Bean对象,也会同时生成ConfigA中的Bean、

11.2 环境设置

@Profile注解。 - @Profile(“development”) - @Profile(“production”)

development/production等均为自定义的环境变量值。可用于设置了某种环境下,执行对应的配置。

@PropertySource(“classpath:/com/myco/app.properties”)

指定属性源文件。

11.3 spring 中的事件机制

步骤: - 定义事件 - 发送事件 - 监听事件,也即处理事件。

11.3.1 定义事件

spring 内置了几类事件。

自定义事件

public class BlockedListEvent extends ApplicationEvent {

    private final String address;
    private final String content;

    public BlockedListEvent(Object source, String address, String content) {
        super(source);
        this.address = address;
        this.content = content;
    }

    // accessor and other methods...
}

11.3.2 发送事件

public class EmailService implements ApplicationEventPublisherAware {

    private List<String> blockedList;
    private ApplicationEventPublisher publisher;

    public void setBlockedList(List<String> blockedList) {
        this.blockedList = blockedList;
    }

    public void setApplicationEventPublisher(ApplicationEventPublisher publisher) {
        this.publisher = publisher;
    }

    public void sendEmail(String address, String content) {
        if (blockedList.contains(address)) {
            publisher.publishEvent(new BlockedListEvent(this, address, content));
            return;
        }
        // send email...
    }
}

ApplicationEventPublisher#publishEvent(),则可发送事件。

11.3.3 监听事件,处理事件

方式一:实现接口

public class BlockedListNotifier implements ApplicationListener<BlockedListEvent> {

    private String notificationAddress;

    public void setNotificationAddress(String notificationAddress) {
        this.notificationAddress = notificationAddress;
    }

    public void onApplicationEvent(BlockedListEvent event) {
        // notify appropriate parties via notificationAddress...
    }
}

方式二:使用注解@EventListener

public class BlockedListNotifier {

    private String notificationAddress;

    public void setNotificationAddress(String notificationAddress) {
        this.notificationAddress = notificationAddress;
    }

    @EventListener
    public void processBlockedListEvent(BlockedListEvent event) {
        // notify appropriate parties via notificationAddress...
    }
}

@EventListener,还可以有些属性,进行针对性监听。可结合@Async、@Order(42)使用