概述

IOC重要思想是:依赖倒置原则(Dependency Inversion Principle )

把自己new对象的方式交给Spring容器去实例化,这就是控制反转思想

IOC控制反转 - 图1

容器概念


在每个框架的中都有一个容器的概念,所谓的容器就是将常用的服务,封装起来,然后,用户只需要遵循一定的规则,就可以达到统一、灵活、安全、方便、快速的目的
具有依赖注入功能的容器,负责实例化、定位、配置应用程序中的对象及建立这些对象间的依赖

IOC负责管理你的任意对象,并结合你对对象的描述进行初始化和加强.
比如,对于一个用注解@Controller声明的对象,Spring会认为这个对象是Web Controller ,如果这个对象里面有方法有@RequestMapping注解,则会将客户端发起的HTTP请求转化成java方法调用.

(一)IOC原理

解析xml配置,获取bean class地址,使用Java的反射机制,进行实例化对象,然后把对象返回.

Spring的IOC实现原理就是工厂模式加反射机制,通俗来讲就是根据给出的类名(字符串方式)来动态地生成对象,这种编程方式可以让对象在生成时才被决定到底是哪一种对象。把IOC容器的工作模式看做是工厂模式的升华,可以把IOC容器看作是一个工厂,这个工厂里要生产的对象都在配置文件中给出定义,然后利用编程语言提供的反射机制,根据配置文件中给出的类名生成相应的对象。

(二)IOC的优缺点


优点
实现组件之间的解耦,提高程序的灵活性和可维护性
缺点
对象 生成因为是使用反射编程,在效率上有些损耗。但相对于IoC提高的维护性和灵活性来说,这点损耗是微不足道的,除非某对象的生成对效率要求特别高

(三)IOC实现原理


Spring 启动时读取应用程序提供的Bean配置信息,并在Spring容器中生成一份相应的Bean配置注册表,然后根据这张注册表实例化Bean,装配好Bean之间的依赖关系,为上层应用提供准备就绪的运行环境。

IOC控制反转 - 图2


Bean缓存池:HashMap实现

Spring 通过一个配置文件描述 Bean 及 Bean 之间的依赖关系,利用 Java 语言的反射功能实例化 Bean 并建立 Bean 之间的依赖关系。 Spring 的 IoC 容器在完成这些底层工作的基础上,还提供了 Bean 实例缓存、生命周期管理、 Bean 实例代理、事件发布、资源装载等高级服务。



BeanFactory 是 Spring 框架的基础设施,面向 Spring 本身;

ApplicationContext 面向使用 Spring 框架的开发者,几乎所有的应用场合我们都直接使用 ApplicationContext 而非底层的 BeanFactory。

IOC控制反转 - 图3


BeanDefinitionRegistry: Spring 配置文件中每一个节点元素在 Spring 容器里都通过一个 BeanDefinition 对象表示,它描述了 Bean 的配置信息。而 BeanDefinitionRegistry 接口提供了向容器手工注册 BeanDefinition 对象的方法。

BeanFactory 接口位于类结构树的顶端 ,它最主要的方法就是 getBean(String beanName),该方法从容器中返回特定名称的 Bean,BeanFactory 的功能通过其他的接口得到不断扩展:

ListableBeanFactory:该接口定义了访问容器中 Bean 基本信息的若干方法,如查看Bean 的个数、获取某一类型 Bean 的配置名、查看容器中是否包括某一 Bean 等方法;

HierarchicalBeanFactory:父子级联 IoC 容器的接口,子容器可以通过接口方法访问父容器; 通过 HierarchicalBeanFactory 接口, Spring 的 IoC 容器可以建立父子层级关联的容器体系,子容器可以访问父容器中的 Bean,但父容器不能访问子容器的 Bean。Spring 使用父子容器实现了很多功能,比如在 Spring MVC 中,展现层 Bean 位于一个子容器中,而业务层和持久层的 Bean 位于父容器中。这样,展现层 Bean 就可以引用业务层和持久层的 Bean,而业务层和持久层的 Bean 则看不到展现层的 Bean。

ConfigurableBeanFactory:是一个重要的接口,增强了 IoC 容器的可定制性,它定义了设置类装载器、属性编辑器、容器初始化后置处理器等方法;

AutowireCapableBeanFactory:定义了将容器中的 Bean 按某种规则(如按名字匹配、按类型匹配等)进行自动装配的方法;

SingletonBeanRegistry:定义了允许在运行期间向容器注册单实例 Bean 的方法;

(四)BeanFactory与ApplicationContext


beanFactory主要是面对与 spring 框架的基础设施,面对 spring 自己。而 Applicationcontex 主要面对与 spring 使用的开发者。日常开发程序员基本都会使用 Applicationcontex 并非 beanFactory 。

1. BeanFactory负责读取bean配置文档,管理bean的加载,实例化,维护bean之间的依赖关系,负责bean的声明周期。

2. ApplicationContext除了提供上述BeanFactory所能提供的功能之外,还提供了更完整的框架功能:a. 国际化支持b. 资源访问:Resource rs = ctx. getResource(“classpath:config.properties”), “file:c:/config.properties”
c. 事件传递:通过实现ApplicationContextAware接口


详细说明,两者对比区别:

https://www.yuque.com/docs/share/bf1e302d-2098-45fb-84a5-47c59b7e745f?#



应用上下文(ApplicationContext)

AnnotationConfigApplicationContext:从一个或多个基于 Java 的配置类中加载 Spring 应用上下文。

AnnotationConfigWebApplicationContext:从一个或多个基于 Java 的配置类中加载 Spring Web 应用上下文。

ClassPathXmlApplicationContext:从类路径下的一个或多个 XML 配置文件中加载上下文定义,把应用上下文的定义文件作为类资源。

FileSystemXmlapplicationcontext:从文件系统下的一个或多个 XML 配置文件中加载上下文定义。

XmlWebApplicationContext:从 Web 应用下的一个或多个 XML 配置文件中加载上下文定义。

有了这些上下文之后,我们可以调用上下文的 getBean() 方法从 Spring 容器中获取 bean。

(五)@ComponentScan

配置扫描包注解
如果不指定,默认从声明@ComponentScan所在类的package进行扫描。正因为如此,SpringBoot的启动类都默认在src/main/java下。
如果配置了就只扫描配置的路径,默认扫描启动类路径下的就会失效,需要注意这一点.


@ComponentScan(basePackages = {“com.lanmili.core.util”,“com.lanmili.rest.*”})

排除的话用excludeFilters属性 , 包含的话,可以用includeFilters

注解包含属性:

basePackages:指定多个包名进行扫描basePackageClasses:对指定的类和接口所属的包进行扫excludeFilters:指定不扫描的过滤器includeFilters:指定扫描的过滤器lazyInit:是否对注册扫描的bean设置为懒加载nameGenerator:为扫描到的bean自动命名resourcePattern:控制可用于扫描的类文件scopedProxy:指定代理是否应该被扫描scopeResolver:指定扫描bean的范围useDefaultFilters:是否开启对@Component,@Repository,@Service,@Controller的类进行检测

1.@ComponentScan.Filter


a)注解形式的FilterType.ANNOTATION @Controller @Service @Repository @Compent
b)指定类型的 FilterType.ASSIGNABLETYPE @ComponentScan.Filter(type =
FilterType.ASSIGNABLE_TYPE,value = {TulingService.class})
c)aspectj类型的 FilterType.ASPECTJ(不常用)
d)正则表达式的 FilterType.REGEX(不常用)
e)自定义的 FilterType.CUSTOM
自定义类型案例参考: 案例:ZJJ_Spring2019/10/12
9:26:16_xa9fz

public enum FilterType {
//注解形式 比如@Controller @Service @Repository @Compent
ANNOTATION,
//指定的类型
ASSIGNABLE_TYPE,
//aspectJ形式的
ASPECTJ,
//正则表达式的
REGEX,
//自定义的
CUSTOM
}

(六)@Component

Spring框架在进行扫描spring.xml 的context标签的时候,会实例化一个扫描器,递归扫描base-package路径下的所有类,判断这些所有类是否有@Component注解,如果有注解就封装BeanDefinition对象.


@Component 作用就是标记这个类,给这个类封装成BeanDefinition对象, 也就是加入到Spring容器里面,但是需要配置@ComponentScan注解

自定义Component注解

默认的@Service 和@Component如果你觉得不好用的话,你可以自定义注解,被自定义注解标注的类会加入到Spring容器里面去

@MyService
public class MyAnnoService { 参考:案例:ZJJSpring2020/02/07 2:13:44_qguex



(七)@Configuration


从Spring3.0,@Configuration用于定义配置类,相当于Spring配置了一个xml配置文件,
配置类里面的@Bean注解在方法上,声明当前方法的返回值为一个Bean.


注意:@Configuration注解的配置类有如下要求:

@Configuration标注在类上,相当于这个类就是一个xml文件,@Bean注解就相当于里面的每一个bean
作用为:配置spring容器(应用上下文)


@Configuation等价于
@Bean等价于
@ComponentScan等价于


一句话概括就是 @Configuration 中所有带 @Bean 注解的方法都会被动态代理,因此调用该方法返回的都是同一个实例。
IOC控制反转 - 图4
从定义来看, @Configuration 注解本质上还是 @Component,因此 或者 @ComponentScan 都能处理@Configuration 注解的类。

@Configuration 标记的类必须符合下面的要求:
@Configuration不可以是final类型(没法动态代理);
@Configuration不可以是匿名类;
嵌套的configuration必须是静态类。
配置类必须以类的形式提供(不能是工厂方法返回的实例),允许通过生成子类在运行时增强(cglib 动态代理)。
配置注解通常为了通过 @Bean 注解生成 Spring 容器管理的类,
配置类必须是非本地的(即不能在方法中声明,不能是 private)。
任何嵌套配置类都必须声明为static。
@Bean 方法可能不会反过来创建进一步的配置类(也就是返回的 bean 如果带有 @Configuration,也不会被特殊处理,只会作为普通的 bean)。

加载过程
Spring 容器在启动时,会加载默认的一些 PostPRocessor,其中就有 ConfigurationClassPostProcessor,这个后置处理程序专门处理带有 @Configuration 注解的类,这个程序会在 bean 定义加载完成后,在 bean 初始化前进行处理。主要处理的过程就是使用 cglib 动态代理增强类,而且是对其中带有 @Bean 注解的方法进行处理。


我们在 @Configuration 注解定义的 bean 方法中可以直接调用方法,不需要 @Autowired 注入后使用。


(九)@Bean, @Component 区别

@Component注解表明一个类会作为组件类,并告知Spring要为这个类创建bean。
@Bean注解告诉Spring这个方法将会返回一个对象,这个对象要注册为Spring应用上下文中的bean。通常方法体中包含了最终产生bean实例的逻辑。(引用第三方类库中的类装配到Spring容器就需要使用@Bean来实现了)
两者的目的是一样的,都是注册bean到Spring容器中。

@Component(@Controller、@Service、@Repository)通常是通过类路径扫描来自动侦测以及自动装配到Spring容器中。
而@Bean注解通常是我们在标有该注解的方法中定义产生这个bean的逻辑。

列子:

@Controller

//在这里用Component,Controller,Service,Repository都可以起到相同的作用。
@RequestMapping(″/web/controller1″)
public class WebController {
…..
}

而@Bean的用途则更加灵活
当我们引用第三方库中的类需要装配到Spring容器时,则只能通过@Bean来实现,而且还可以根据情况进行更灵活的装配bean

@Bean
public OneService getService(status) {
case (status) {
when 1:
return new serviceImpl1();
when 2:
return new serviceImpl2();
when 3:
return new serviceImpl3();
}
}


总结:@Component和@Bean都是用来注册Bean并装配到Spring容器中,但是Bean比Component的自定义性更强。可以实现一些Component实现不了的自定义加载类。


在@Component类中使用方法或字段时不会使用CGLIB增强(及不使用代理类:调用任何方法,使用任何变量,拿到的是原始对象,后面会有例子解释)。而在@Configuration类中使用方法或字段时则使用CGLIB创造协作对象(及使用代理:拿到的是代理对象);当调用@Bean注解的方法时它不是普通的Java语义,而是从容器中拿到的由Spring生命周期管理、被Spring代理甚至依赖于其他Bean的对象引用。在@Component中调用@Bean注解的方法和字段则是普通的Java语义,不经过CGLIB处理。

(十)@Component和@Configuration作为配置类实例化@Bean的差别


@Component 里面的bean对象不是Spring容器里面的对象.

@Configuration 里面的bean对象是Spring容器里面的对象


默认情况下是 @Configuration是随容器启动开始加载的,始终存在的单例模式。 @Component是使用一次即实例化一次

参考:

https://www.yuque.com/docs/share/49d99d09-f7e3-42c7-9508-29a1dcb96e18?#

(十一)往IOC 容器中添加组件的方式

案例:ZJJ_Spring2019/10/12_10:24:02_cby1u


1.:通过@CompentScan +@Controller @Service @Respository @compent
适用场景: 针对我们自己写的组件可以通过该方式来进行加载到容器中。
2.:通过@Bean的方式来导入组件(适用于导入第三方组件的类)
3.:通过@Import来导入组件 (导入组件的id为全类名路径)

@import使用场景是SpringBoot自动装配,

@Configuration
@Import(value = {Person.class, Car.class})
public class MainConfig {
}


通过@Import 的ImportSeletor类实现组件的导入 (导入组件的id为全类名路径)

public class TulingImportSelector implements ImportSelector {
/可以获取导入类的注解信息
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{“com.tuling.testimport.compent.Dog”};
}
}
@Configuration
@Import(value = {Person.class, Car.class, TulingImportSelector.class})
public class MainConfig {
}


通过@Import的 ImportBeanDefinitionRegister导入组件 (可以指定bean的名称)

public class TulingBeanDefinitionRegister implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
BeanDefinitionRegistry registry) {
//创建一个bean定义对象
RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(Cat.class);
//把bean定义对象导入到容器中
registry.registerBeanDefinition(“cat”,rootBeanDefinition);
}
}
@Configuration
//@Import(value = {Person.class, Car.class})
//@Import(value = {Person.class, Car.class, TulingImportSelector.class})
@Import(value = {Person.class, Car.class, TulingImportSelector.class, TulingBeanDefinitionRegister.class})
public class MainConfig {
}


4. 通过实现FacotryBean接口来实现注册组件
使用场景是复杂的初始化,就是Bean初始化需要设置很多很多的组件,比较大的就建议用这种方式去配置,典型的例子就是SqlSessionFactoryBean

public class CarFactoryBean implements FactoryBean {

/返回bean的对象
@Override
public Car getObject() throws Exception {
return new Car();
}

/返回bean的类型
@Override
public Class<?> getObjectType() {
return Car.class;
}

/是否为单利
@Override
public boolean isSingleton() {
return true;
}
}


1.initMethod和destroyMethod方式

initMethod和destroyMethod方式实现Bean的初始化和销毁

@Configuration
@ComponentScan(basePackages = “F_bean的生命周期”)
public class MainConfig {

@Scope(value = “prototype”)
@Bean(initMethod = “init”, destroyMethod = “destroy”)//指定类的init方法和destroy方法 public Car car() {
return new Car();
}


针对单实例bean的话,容器启动的时候,bean的对象就创建了,而且容器销毁的时候,也会调用Bean的销毁方法
针对多实例bean(多例模式)的话,容器启动的时候,bean是不会被创建的而是在获取bean的时候被创建,而且bean的销毁不受IOC容器的管理(多例模式是GC垃圾回收器管理的,不是IOC管理的).

2.InitializingBean和DisposableBean

案例:ZJJSpring_2020/02/15 3:54:59_dwn4p


如果需要在一个类实例化以后去做一些事情,那么就可以借助InitializingBean这个接口来完成,比如在bean实例化需要做xml解析,或者资源的开启释放,加载预热缓存等等,都可以用InitializingBean这个接口来实现.

通过InitializingBean和DisposableBean 的二个接口实现bean的初始化以及销毁方法

InitializingBean接口为bean提供了初始化方法的方式,它只包括afterPropertiesSet方法,凡是继承该接口的类,在初始化bean的时候都会执行该方法。

关于 InitializingBean的具体看
https://mp.weixin.qq.com/s?__biz=MzI5NTYwNDQxNA==&mid=2247484595&idx=4&sn=d8de987a336a08333c7fef423289c175&chksm=ec505d62db27d47480967e2249db20f22479ec7ac1ab61a2bf7ec80018de03a6339b6c74b617&scene=7&key=34c4aa20c67724dd4a68a71c8e465811169ac1bf709249a547b4ae2d58914e00287a1d836dc6106e7f8348faba734fce94bec00c1c5d5a486ecdbdafef5cf0a3b19d0377a93183644b649f3b53911acd&ascene=0&uin=MTQwMjAyODM3MA%3D%3D&devicetype=Windows+7&version=62070158&lang=zh_CN&exportkey=A8q3Ea45yuIiFB1HyJjMIcs%3D&pass_ticket=xlBM9daG3yq8iOb%2FIUpOZUh6Ytdj%2BUZ0rPH5F%2BpDs1Lu6ao81UIDGF1ldr9J98mz

@Component
public class Person implements InitializingBean, DisposableBean {

public Person() {
System.out.println(“Person的构造方法”);
}

@Override
public void destroy() throws Exception {
System.out.println(“DisposableBean的destroy()方法 “);
}

/
该方法在 BeanFactory 设置完了所有属性之后被调用
该方法允许 bean 实例设置了所有 bean 属性时执行初始化工作,如果该过程出现了错误则需要抛出异常
*/
@Override
public void afterPropertiesSet
() throws Exception {
System
.out.println(“InitializingBean的 afterPropertiesSet方法”);
}
}**


3.bean实例化的时候加载东西 @PostConstruct 和@ProDestory

案例:ZJJSpringBoot_2020/02/06 5:03:06_pq7hc


@PostConstruct用来标记是在Bean实例化之后加载完依赖注入后执行这个方法。用来修饰一个非静态的void()方法,也就是Spring容器启动时就执行,多用于一些全局配置、数据字典之类的加载.同时只会被服务器执行一次。PostConstruct在构造函数之后执行,init()方法之前执行。PreDestroy()方法在destroy()方法执行执行之后执

@PostConstruct总体概述

1. 要在依赖加载后,对象使用前执行,而且只执行一次,原因在上面已经说了。
2. 所有支持依赖注入的类都要支持此方法。
3. 文档中说一个类只能有一个方法加此注解,但实际测试中,我在一个类中多个方法加了此注解,并没有报错,而且都执行了,我用的是 Spring Boot 框架。


@PostConstruct注释规则

1. 除了拦截器这个特殊情况以外,其他情况都不允许有参数,否则spring框架会报IllegalStateException;而且返回值要是void,但实际也可以有返回值,至少不会报错,只会忽略
2. 方法随便你用什么权限来修饰,public、protected、private都可以,反正功能是由反射来实现3. 方法不可以是static的,但可以是final的所以,综上所述,在spring项目中,在一个bean的初始化过程中,方法执行先后顺序为:
Constructor > @Autowired > @PostConstruct先执行完构造方法,再注入依赖,最后执行初始化操作,所以这个注解就避免了一些需要在构造方法里使用依赖组件的尴尬。

@PostConstruct实现原理

参考:
https://www.yuque.com/docs/share/68f9d4e9-e2e7-4e5a-b857-4fa6e46dfd4c?#


@PreDestroy 和 @PostConstruct差不多

被@PreDestroy修饰的方法会在Bean销毁之前执行被这个注解修饰的方法

4.BeanPostProcessor后置处理器



通过Spring的BeanPostProcessor的 bean的后置处理器会拦截所有bean创建过程

使用场景:
用来修改Bean的一些属性的,可以在postProcessBeforeInitialization()方法里面进行修改

postProcessBeforeInitialization 在init方法之前调用
postProcessAfterInitialization 在init方法之后调用

/
后置处理器 在bean调用初始化方法前后进行调用 BeanPostProcessor左右:在bean的初始化前后进行调用 */
@Component
public class TulingBeanPostProcessor implements BeanPostProcessor {

/

在初始化之前
@param bean
__
@param beanName
__
*
@return
*
@throws BeansException
/
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println(“TulingBeanPostProcessor…postProcessBeforeInitialization:” + beanName);
return bean;
}

/**
在初始化之后
@param bean
__
*
@param beanName
__
*
@return
*
@throws BeansException
/
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println(“TulingBeanPostProcessor…postProcessAfterInitialization:” + beanName);
*return
bean;
}



BeanPostProcessor的执行时机

populateBean(beanName, mbd, instanceWrapper)
initializeBean{
applyBeanPostProcessorsBeforeInitialization()
invokeInitMethods{
isInitializingBean.afterPropertiesSet
自定义的init方法
}
applyBeanPostProcessorsAfterInitialization()方法
}

(十二)@Value+@PropertySource给组件赋值

案例:ZJJ_Spring2019/10/12_12:14:31_glj4b


@Value(“${person.lastName}”)
private String lastName;


@PropertySource(value = {“classpath:person.properties”}) //导入属性文件注解

EmbeddedValueResolverAware解析配置文件的值

EmbeddedValueResolverAware是内嵌的值解析器

案例:ZJJSpring2019/10/1213:29:241469a @Configuration
@PropertySource(value = {“classpath:ds.properties”})
public class MainConfig implements EmbeddedValueResolverAware { private String jdbcUrl;

private String classDriver;

/
解析配置文件的值,可以给形参赋值
@param _resolver
*/
@Override
public void setEmbeddedValueResolver(StringValueResolver resolver) {
this.jdbcUrl = resolver.resolveStringValue(“${ds.jdbcUrl}”);
this.classDriver = resolver.resolveStringValue(“${ds.classDriver}”**);
}



(十三)@AutoWired自动装配和@Qualifier


如果在一个类里面,不管是属性注入还是构造注入或者是方法注入,都会触发需要依赖的这个引用数据类型的getBean的操作.getBean第一次是实例化对象,后面大部分是从IOC容器缓存里面获取.


自动装配首先时按照类型进行装配,若在IOC容器中发现了多个相同类型的组件,那么就按照属性名称来进行装配.

@Autowired
private TulingDao tulingDao;
比如,我容器中有二个TulingDao类型的组件 一个叫tulingDao 一个叫tulingDao2那么我们通过@AutoWired 来修饰的属性名称时tulingDao,那么拿就加载容器的tulingDao组件,若属性名称为tulignDao2 那么他就加载的时tulingDao2组件

在两个TulingDao类型的组件中假设我们需要指定特定的组件来进行装配,我们可以通过使用@Qualifier(“tulingDao”)来指定装配的组件或者在配置类上的@Bean加上@Primary注解

@Autowired
@Qualifier(“tulingDao”) //这样装备的就是tulingDao
private TulingDao tulingDao2




假设我们容器中即没有tulingDao 和tulingDao2,那么在装配的时候就会抛出异常
No qualifying bean of type ‘com.tuling.testautowired.TulingDao’ available
若我们想不抛异常 ,我们需要指定 required为false的时候可以了

@Autowired(required = false)
@Qualifier(“tulingDao”)
private TulingDao tulingDao2;




标注在set方法上
标注set方法上的话,作用的对象是这个set方法的形参TulingLog tulingLog
然后set方法内部就会对成员类进行赋值操作.

@Autowired
public void setTulingLog(TulingLog tulingLog) {
this.tulingLog = tulingLog;
}


标注在构造方法上
标注构造方法上的话,作用的对象是这个构造方法的形参TulingLog tulingLog
然后构造方法内部就会对成员类进行赋值操作.

@Autowired
public TulingAspect(TulingLog tulingLog) {

this.tulingLog = tulingLog;
}

标注在配置类上的入参中(可以不写)

@Bean
public TulingAspect tulingAspect(@Autowired TulingLog tulingLog) {
TulingAspect tulingAspect = new TulingAspect(tulingLog);
return tulingAspect;
}


可以给Map里面进行自动注入,被注入的对象都需要实现泛型的接口(EntStrategy)

@Component
public class DefaultStrategy implements EntStrategy {

@Component
public class EntAStrategy implements EntStrategy {

上面是别的类

@Component
public class EntStrategyHolder {

// 关键功能 Spring 会自动将 EntStrategy 接口的类注入到这个Map中,Map的key是bean的名字,默认是首字母小写.

@Autowired
private Map entStrategyMap;

public EntStrategy getBy(String entNum) {
return entStrategyMap.get(entNum);
}
}


注入到List里面
使用上和上面注入到Map里面是一样的,被注入的值需要实现EntStrategy接口

@Autowired
private List entStrategyList;

@Qualifier


https://blog.csdn.net/qq_41489540/article/details/81056918详细介绍
作用:在自动按照类型注入的基础之上,再按照bean的id注入。
属性:
value:用于指定bean的id。


@Qualifier(“名字”):和@Autowired配合使用,可以根据名字注入byName,

注意:
在给类成员注入时,它不能独立使用。必须配合@Autowired如果没有就报错)
但是给方法参数注入时,它可以独立使用(待会再讲)

@Profile根据运行时环境选择装配


@Profile标识在类上,那么只有当前环境匹配,整个配置类才会生效
@Profile标识在Bean上 ,那么只有当前环境的Bean才会被激活
没有标志为@Profile的bean 不管在什么环境都可以被激活

案例:ZJJ_Spring2019/10/12_13:21:05_qgcaq


@Bean
@Profile(value = “dev”) //如果是dev环境就装配bean public DataSource devDs() {
return buliderDataSource(new DruidDataSource());
}

@Bean
@Profile(value = “prod”) // 如果是prod环境就装配bean public DataSource prodDs() {
return buliderDataSource(new DruidDataSource());
}



获取容器环境,同时设置容器环境

public static void main(String[] args) {
/ AnnotationConfigApplicationContext ctx =
new AnnotationConfigApplicationContext(MainConfig.class);
/

AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
// ctx.getEnvironment().setActiveProfiles(“test”,”dev”);//配置运行时环境,在开发的时候一般设置一个.不会设置两个 ctx.getEnvironment().setActiveProfiles(“test”);
ctx.register(MainConfig.class); //注册一个或多个要处理的带annotated的类 ctx.refresh(); //返回静态指定的ApplicationListeners列表 printBeanName(ctx);
}



优先选择的 Bean

我们都知道面向接口编程,就像我们 MVC 三层结构中 Controller 中注入一个 Service, 而这个 Service 的接口存在多个实现类时,Spring 会报 NoUniqueBeanDefinitionException 异常。因为 Spring 无法自主的去选择一个合适的实现类。这时我们需要给 Spring 提供帮助,让他能够找到合适的首选(primary)的 Bean。

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


(十四)注入static修饰的类变量

@Configuration
public class CeuiUtils {
@Autowired
/任务管理,可以做任务的查询的/
private TaskService _taskService;
private static TaskService taskService;

@PostConstruct //这个注解是重点
public void init() {
this.taskService = _taskService;
}

public static void ceui() {
System.out.println(“——-“ + taskService); // 这里能打印出来地址值
}

}




(十五)Spring Bean初始化/销毁


日常开发过程有时需要在应用启动之后加载某些资源,或者在应用关闭之前释放资源。Spring 框架提供相关功能,围绕 Spring Bean 生命周期,可以在 Bean 创建过程初始化资源,以及销毁 Bean 过程释放资源。Spring 提供多种不同的方式初始化/销毁 Bean,如果同时使用这几种方式,Spring 如何处理这几者之间的顺序?



参考:
https://www.yuque.com/docs/share/f3cd8664-1134-493b-bdfb-7b9c4633653f?#



(十六)@Required

在生产规模的应用程序中,IoC容器中可能会有数百或数千个bean,并且它们之间的依赖关系通常非常复杂。setter注入的一个缺点是你很难检查是否已经设置了所有必需的属性。使用“ dependency-check”属性可以检查属性值是否已设置,但无法检查其值是否设置为null或non-null值。
除了使用验证依赖项之外dependency-check,您还可以使用@Required注释来检查是否设置了值non-null。


https://www.yuque.com/docs/share/7f5a3158-8ee0-441e-a5dd-3b8c581fc7e1?#

(十七)@PostConstruct


该注解可以实现在运行工程时,自动运行该注解下的方法,指的是在项目启动的时候执行这个方法,也可以理解为在spring容器启动的时候执行,可作为一些数据的常规化加载,比如数据字典之类的。

被@PostConstruct修饰的方法会在服务器加载Servle的时候运行,并且只会被服务器执行一次。PostConstruct在构造函数之后执行
也就是加载顺序
服务器加载Servlet -> servlet 构造函数的加载 -> postConstruct ->init(init是在service 中的初始化方法. 创建service 时发生的事件.) ->Service->destory->predestory->服务器卸载serlvet
那么问题:spring中Constructor、@Autowired、@PostConstruct的顺序Constructor >> @Autowired >> @PostConstruct
依赖注入的字面意思就可以知道,要将对象p注入到对象a,那么首先就必须得生成对象p与对象a,才能执行注入。所以,如果一个类A中有个成员变量p被@Autowired注解,那么@Autowired注入是发生在A的构造方法执行完之后的。
@PostConstruct应用场景:
如果想在生成对象时候完成某些初始化操作,而偏偏这些初始化操作又依赖于依赖注入,那么就无法在构造函数中实现。为此,可以使用@PostConstruct注解一个方法来完成初始化,@PostConstruct注解的方法将会在依赖注入完成后被自动调用。


@PostConstructor 和 afterPropertiesSet的功能是一样的.


(十八)@DependsOn


@DependsOn注解可以配置Spring IoC容器在初始化一个Bean之前,先初始化其他的Bean对象。