您的位置:首页 > 编程语言 > Java开发

Spring逐点击破(一)—依赖(Bean)注入的几种方式(全)

2018-12-18 22:28 337 查看
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u013035271/article/details/85082627

最近在系统的学习Spring相关的知识点,准备在整理出一个Spring的知识架构体系,这是第一篇。

一、XML注入Bean

这种方式,相信绝大多数使用过Spring的朋友都轻车熟路。

  • 首先创建一个我们需要注入到IOC容器的Bean测试类
package com.trinclesdar.beans;

import lombok.AllArgsConstructor;
import lombok.Data;

@Data
@AllArgsConstructor
public class Person {
private String name;
private Integer age;

public Person(){
super();
}

@Override
public String toString() {
return "Person \n [name=" + name + ", age=" + age + "]";
}
}
  • 在resources目录下创建beans.xml,通常在项目中,这个文件我们通常命名为applicationContext.xml
<?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">

<bean id="person" class="com.trinclesdar.bean.Person">
<property name="name" value="trinclesdar"/>
<property name="age" value="18"/>
</bean>
</beans>
  • 测试
package com.trinclesdar.test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class XMLBeanInjectTest {
public static void main(String args[]){
//把beans.xml的类加载到容器
ApplicationContext app = new ClassPathXmlApplicationContext("beans.xml");
//从容器中获取bean
Person person = (Person) app.getBean("person");
System.out.println(person);
}
}
  • 结果

二、Spring注解注入Bean(@Configuration)

1. @Bean

  • 首先,同样创建一个项目需要使用到的Bean类:
package com.trinclesdar.study.spring.bean;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
* 定义需要注入到IOC容器的bean
*
* @author trinclesdar
* @date 2018/11/4 17:22
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class TestBean1 {

private String property1;
private Integer property2;

}
  • 通过@Bean导入组件
package com.trinclesdar.study.spring.beaninject;

import com.trinclesdar.study.spring.bean.TestBean1;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;

/**
* bean注入IOC容器
*
* @author trinclesdar
* @date 2018/11/4 17:13
*/
@Configuration
public class BeanInjectByAnno {

@Bean("testBean1")
public TestBean1 injectBean() {
return new TestBean1("testBean1", 1);
}
}

@Configuration注解的作用是声明该类是一个配置类,其效果等同于我们声明的applicationContext.xml文件,@Bean的作用是在Spring容器启动时,告诉容器这是一个SpringBean,将会注入到Spring的IOC容器,效果等同于在applicationContext.xml中声明的bean标签。

  • 测试
package com.trinclesdar.study.spring.beaninject;

import com.trinclesdar.study.spring.bean.TestBean1;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;

/**
* bean注入IOC容器
*
* @author trinclesdar
* @date 2018/11/4 17:13
*/
@Configuration
}, useDefaultFilters = false)
public class BeanInjectByAnno {

/**
* 指定单例or多例模式
* 单实例的bean,在容器关闭时,会调用bean的destroy()方法销毁bean实例,
* 而多实例的bean,容器只负责在调用bean的时候生成bean,但容器不会管理bean的生命周期,
* 在容器关闭时,也不会调用destroy()方法销毁bean
*
* @return TestBean1
*/
@Scope("prototype")
@Bean("testBean1")
// @Lazy
public TestBean1 injectBean() {
System.out.println("初始化容器标记");
return new TestBean1("testBean1", 1);
}
}

@Bean(“testBean1”)注解中的"testBean1",用于指定注入Bean的对象名,如果不配置,则Spring容器默认将方法名,即上述代码中的"injectBean",作为对象名,注入到容器中。@Bean通常用于导入第三方组件,如我们项目中数据库相关的Bean、各种模板组件等等。

  • @Scope注解有两个属性,"prototype"和"singleton",用于指定该Bean在注入IOC容器时,是以单实例模式("singleton"),还是多实例模式("prototype")注入。
  • 多实例:IOC容器启动时,并不会去调用初始化方法创建对象,而是每次获取的时候才会调用方法创建对象;
  • 单实例(默认):IOC容器启动时,会调用初始化方法创建对象,并将对象放到IOC容器的"Big Map"中,以后每需要获取bean就直接从容器获取,不重复初始化。

如果不配置该注解,则Spring默认以单实例(“singleton”)模式,创建该Bean对象。

  • @Lazy,该注解主要用于@Scope("singleton"),即单实例Bean下,当我们加上该注解时,Spring容器在启动过程中,并不会去创建和初始化对应的Bean,而是当且仅当我们调用了anno.getBean()方法,即当我们第一次需要使用(获取)Bean的时候,才会去创建和初始化对应的Bean。
  • @Condition 在某些项目场景下,我们需要根据不同的条件,往容器中注入不同类型的Bean实例,比如,在Windows操作系统下,和Linux操作系统下,我们需要根据操作类型的不同,注入不同类型的Bean,这时候,我们就可以使用这个注解来实现。

新建两个实现org.springframework.context.annotation.Condition接口的类:

package com.enjoy.cap5.config;

import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotatedTypeMetadata;

/**
* 注入Bean的条件
*
* @author trinclesdar
* @date 2018/11/6 22:25
*/
public class WinCondition implements Condition {

/**
* ConditionContext: 判断条件可以使用的上下文(环境)
* AnnotatedTypeMetadata: 注解的信息
*/
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
// 是否为WINDOW系统
//能获取到IOC容器正在使用的beanFactory
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
//获取当前环境变量(包括我们操作系统是WIN还是LINUX??)
Environment environment = context.getEnvironment();
String osName = environment.getProperty("os.name");
return osName.contains("Windows");
}
}
package com.enjoy.cap5.config;

import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotatedTypeMetadata;

/**
* 注入Bean的条件
*
* @author trinclesdar
* @date 2018/11/6 22:26
*/
public class LinCondition implements Condition {
/**
* ConditionContext: 判断条件可以使用的上下文(环境)
* AnnotatedTypeMetadata: 注解的信息
*/
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
// 是否为Linux系统
//能获取到IOC容器正在使用的beanFactory
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
//获取当前环境变量(包括我们操作系统是WIN还是LINUX??)
Environment environment = context.getEnvironment();
String osName = environment.getProperty("os.name");
return osName.contains("linux");
}
}

新建配置类:

package com.trinclesdar.study.spring.beaninject;

import com.trinclesdar.study.spring.bean.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;

/**
* 根据不同操作系统,注入不同类型bean
*
* @author trinclesdar
* @date 2018/11/6 22:30
*/
@Configuration
public class BeanInjectByCondition {
@Bean("person")
public Person person() {
System.out.println("给容器中添加person.......");
return new Person("person", 20);
}

@Conditional(WinCondition.class)
@Bean("trinclesdar")
public Person trinclesdar() {
System.out.println("给容器中添加trinclesdar.......");
return new Person("trinclesdar", 18);
}

@Conditional(LinCondition.class)
//bean在容器中的ID为jayChou, IOC容器MAP,  map.put("id",value)
@Bean("jayChou")
public Person jayChou() {
System.out.println("给容器中添加周杰伦.......");
return new Person("周杰伦", 100);
}
}

如上,如果操作系统为Windows,则向容器注入一个trinclesdar的实例对象,如果系统为Linux,则为容器注入一个周杰伦对象。

测试

@Test
public void test01(){
AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(Cap5MainConfig.class);
System.out.println("IOC容器创建完成........");
}

我当前操作系统是Windows,因此为Spring容器注入的Bean实例为trinclesdar。

2. @Component

我们常用的@Controller、@Service等注解,都是默认实现了@Component,该注解用于声明某个类可以作为Spring Bean,在容器初始化过程中,被扫描和自动注入至容器,供其它类调用,其用法与@Controller和@Service相似。

package org.springframework.stereotype;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.stereotype.Component;

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Controller {
String value() default "";
}

3. @ComponentScan

新建几个我们熟悉的测试包和类,也就是我们项目中常用的controller、service…

package com.trinclesdar.study.spring.bean.controller;

import com.trinclesdar.study.spring.bean.service.TestService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;

/**
* 测试Controller
*
* @author trinclesdar
* @date 2018/11/4 18:00
*/
@Controller
public class TestController {

@Autowired
@Qualifier("service")
private TestService testService;

}
package com.trinclesdar.study.spring.beaninject;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
package com.trinclesdar.study.spring.bean.service;

import org.springframework.stereotype.Service;

/**
* 测试Service
*
* @author trinclesdar
* @date 2018/11/6 21:49
*/
@Service
public class TestService {
}
</code></pre>

通过@ComponentScan注解声明Bean扫描范围

<pre><code class="language-java line-numbers">/**
* 通过@ComponentScan指定扫描范围
* 注:@ComponentScan注解会扫描指定范围的包下所有声明了@Component注解的Bean,@Controller、@Service等注解,其实都是引入了@Component注解的
*
* @author LiaoDebin
* @date 2018/11/4 17:58
*/
@Configuration
@ComponentScan(value = "com.trinclesdar.study.spring")
public class BeanInjectByComponentScan {

}

测试

@Test
public void beanInjectByComponentScan() {
// 声明容器,将BeanInjectByComponentScan类的配置信息加载至容器中
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(BeanInjectByComponentScan.class);

// 获取容器中所有的bean名称
String[] beanNames = applicationContext.getBeanDefinitionNames();
System.out.println("beanNames:");
for (String beanName : beanNames) {
System.out.println(beanName);
}
}
可以看到,在容器初始化之后,已经将指定范围下("com.trinclesdar.study.spring")下的所有Bean注入到容器中,也包括了我们新加入的Controller和Service组件对象。

@ComponentScan用于指定在Spring容器启动时,扫描容器的包范围,默认只需要指定value的属性值即可,同时可以配合includeFilters和excludeFilters属性,进一步过滤容器扫描Bean的范围。

package com.trinclesdar.study.spring.beaninject;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;

/**
* 通过@ComponentScan指定扫描范围
* 注:@ComponentScan注解会扫描指定范围的包下所有声明了@Component注解的Bean,@Controller、@Service等注解,其实都是引入了@Component注解的
*
* @author trinclesdar
* @date 2018/11/4 17:58
*/
@Configuration
@ComponentScan(value = "com.trinclesdar.study.spring", includeFilters = {
@ComponentScan.Filter(type = FilterType.CUSTOM, classes = {TestTypeFilter.class})
}, useDefaultFilters = false)
public class BeanInjectByComponentScan {

}
package com.trinclesdar.study.spring.beaninject;

import org.springframework.core.io.Resource;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.ClassMetadata;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.TypeFilter;

import java.io.IOException;

/**
* 包扫描过滤器
*
* @author trinclesdar
* @date 2018/11/4 17:13
*/
public class TestTypeFilter implements TypeFilter {

/**
* MetadataReader:读取到当前正在扫描类的信息
* MetadataReaderFactory:可以获取到其他任何类信息
*/
@Override
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
//获取当前类注解的信息
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
//获取当前正在扫描的类信息
ClassMetadata classMetadata = metadataReader.getClassMetadata();
//获取当前类资源(类的路径)
Resource resource = metadataReader.getResource();

String className = classMetadata.getClassName();
System.out.println("----->" + className);
//当类包含er字符, 则匹配成功,返回true
return className.contains("controller");
}
}

通过以上代码,就可以在Spring容器启动时,将指定范围下,所有Controller组件注入到容器中。

  • @ComponentScan.Filter:声明过滤器类型,type取值有5种类型:
    ANNOTATION:通过注解过滤,如Controller.class、Service.class、Respository.class等;
    ASSIGNABLE_TYPE:按照给定的类型过滤;比如TestService类型;
    ASPECTJ:使用ASPECTJ表达式;
    REGEX:通过正则过滤;
    CUSTOM:自定义过滤器,示例代码中,使用的就是这种方式,使用该方式,需要自定义一个实现TypeFilter接口的过滤器类。
  • useDefaultFilters:该属性表示,是否扫描value指定路径下所有的Bean,该属性默认为true,如果要使用自定义过滤规则,该值必须指定为false,否则过滤器不会生效。

使用场景:@ComponentScan使用与自定义组件(Bean)。

4. @Import

@Import适用于快速给容器导入一个组件,使用方便,但是其弊端在于,引入至容器中的是一个全类名。

package com.trinclesdar.study.spring.beaninject;

import com.trinclesdar.study.spring.bean.TestBean1;
import org.springframework.context.annotation.Import;

/**
* 通过Import注入bean至IOC容器
*
* @author trinclesdar
* @date 2018/11/4 18:23
*/
@Import(value = {TestBean1.class})
public class BeanInjectByImport {

}
@Test
public void beanInjectByImport() {
// 声明容器,将BeanInjectByComponentScan类的配置信息加载至容器中
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(BeanInjectByImport.class);

// 获取容器中所有的bean名称
String[] beanNames = applicationContext.getBeanDefinitionNames();
System.out.println("beanNames:");
for (String beanName : beanNames) {
System.out.println(beanName);
}
}

可以看到,注入到容器中的Bean,是一个类型为com.trinclesdar.study.spring.bean.TestBean1的实例。使用@Import注解,可以不用声明@Configuration注解。容器便会在初始化时,自动将@Import后声明的Bean,注入到容器。

  • ImportSelector

声明两个空的Bean类TestBean2、TestBean3

package com.trinclesdar.study.spring.bean;

/**
*TestBean2
*
* @author trinclesdar
* @date 2018/11/6 22:17
*/
public class TestBean2 {
}
package com.trinclesdar.study.spring.bean;

/**
*TestBean3
*
* @author trinclesdar
* @date 2018/11/6 22:18
*/
public class TestBean3 {
}

新建一个BeanInjectByImportSelector类,实现org.springframework.context.annotation.ImportSelector接口,并实现selectImports()方法,该方法返回一个字符数组,数组中放的是我们需要注入至容器的Bean实例的全路径名。

package com.trinclesdar.study.spring.beaninject;

import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;

/**
* 通过ImportSelector引入bean
*
* @author trinclesdar
* @date 2018/11/6 22:13
*/
public class BeanInjectByImportSelector implements ImportSelector {

@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
return new String[]{"com.trinclesdar.study.spring.bean.TestBean2", "com.trinclesdar.study.spring.bean.TestBean3"};
}
}

将BeanInjectByImportSelector.clas追加至@Import的value属性中,需要注意的是,value属性可以是一个字符串,也可以是一个数组,为数组时,可以声明多个组件,同时也不仅限于我们直接声明的Bean类,也支持ImportSelector和ImportBeanDefinitionRegistrar类型的组件。

package com.trinclesdar.study.spring.beaninject;

import com.trinclesdar.study.spring.bean.TestBean1;
import org.springframework.context.annotation.Import;

/**
* 通过Import注入bean至IOC容器
*
* @author trinclesdar
* @date 2018/11/4 18:23
*/
@Import(value = {TestBean1.class, BeanInjectByImportSelector.class})
public class BeanInjectByImport {

}

创建测试方法

@Test
public void beanInjectByImport() {
// 声明容器,将BeanInjectByComponentScan类的配置信息加载至容器中
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(BeanInjectByImport.class);
// 获取容器中所有的bean名称
String[] beanNames = applicationContext.getBeanDefinitionNames();
System.out.println("beanNames:");
for (String beanName : beanNames) {
System.out.println(beanName);
}
}

运行测试用例,通过结果可以看出,我们想要注入容器的TestBean2、TestBean3已经成功注入到容器中。

  • FactoryBean

新建一个TestBean5,作为测试Bean

package com.trinclesdar.study.spring.bean;

/**
* TestBean5
*
* @author LiaoDebin
* @date 2018/11/6 22:25
*/
public class TestBean5 {
}

声明一个实现FactoryBean接口的TestFactoryBean类,并实现对应接口方法, getObject()、 getObjectType()、isSingleton(),方法的具体含义和目的,可以参见代码中的注释。

package com.trinclesdar.study.spring.beaninject;

import com.trinclesdar.study.spring.bean.TestBean5;
import org.springframework.beans.factory.FactoryBean;

/**
* 通过FactoryBean注入bean
*
* @author trinclesdar
* @date 2018/11/6 22:30
*/
public class TestFactoryBean implements FactoryBean {

/**
* 声明注入至容器的Bean实例对象
*
* @return TestBean5
* @throws Exception 抛出异常
*/
@Override
public TestBean5 getObject() throws Exception {
return new TestBean5();
}

/**
* 声明注入容器的Bean类型
*
* @return TestBean5
*/
@Override
public Class getObjectType() {
return TestBean5.class;
}

/**
* 声明是否以单例模式注入容器
*
* @return boolean
*/
@Override
public boolean isSingleton() {
return false;
}
}

创建测试用例:

@Test
public void beanInjectByFactoryBean() {

AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(BeanInjectByFactoryBean.class);

Object testBean = applicationContext.getBean("testFactoryBean");

System.out.println("testBean Type:" + testBean.getClass());

applicationContext.close();
}

可以看到,类型为TestBean5的Bean实例已经成功注入容器。

  • ImportBeanDefinitionRegistrar

同样,新建一个测试Bean类。

package com.trinclesdar.study.spring.bean;

/**
* TestBean4
*
* @author trinclesdar
* @date 2018/11/6 22:25
*/
public class TestBean4 {
}

新建一个实现org.springframework.context.annotation.ImportBeanDefinitionRegistrar接口的BeanInjectByImportBeanDefinitionRegistrar类。

package com.trinclesdar.study.spring.beaninject;

import com.trinclesdar.study.spring.bean.TestBean4;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;

/**
* 通过ImportBeanDefinitionRegistrar注入Bean
*
* @author trinclesdar
* @date 2018/11/6 22:24
*/
public class BeanInjectByImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {

@Override
public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {
boolean bean1 = beanDefinitionRegistry.containsBeanDefinition("com.trinclesdar.study.spring.bean.TestBean2");
boolean bean2 = beanDefinitionRegistry.containsBeanDefinition("com.trinclesdar.study.spring.bean.TestBean3");
//如果TestBean2和TestBean3同时存在于我们IOC容器中,那么创建TestBean4类, 加入到容器
//对于我们要注册的bean, 给bean进行封装,
if (bean1 && bean2) {
RootBeanDefinition beanDefinition = new RootBeanDefinition(TestBean4.class);
beanDefinitionRegistry.registerBeanDefinition("testBean4", beanDefinition);
}
}
}

最后,将BeanInjectByImportBeanDefinitionRegistrar.class类型追加至@Importor注解中。

package com.trinclesdar.study.spring.beaninject;

import com.trinclesdar.study.spring.bean.TestBean1;
import org.springframework.context.annotation.Import;

/**
* 通过Import注入bean至IOC容器
*
* @author trinclesdar
* @date 2018/11/4 18:23
*/
@Import(value = {TestBean1.class, BeanInjectByImportSelector.class, BeanInjectByImportBeanDefinitionRegistrar.class})
public class BeanInjectByImport {

}

测试

@Test
public void beanInjectByImport() {
// 声明容器,将BeanInjectByComponentScan类的配置信息加载至容器中
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(BeanInjectByImport.class);
// 获取容器中所有的bean名称
String[] beanNames = applicationContext.getBeanDefinitionNames();
System.out.println("beanNames:");
for (String beanName : beanNames) {
System.out.println(beanName);
}
}

效果如预料的一样,testBean4成功注入容器,我们在registerBeanDefinitions()方法中,声明的组件名称为testBean4,那么注入容器的名称则为testBean4,如果我们改为:

public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {
boolean bean1 = beanDefinitionRegistry.containsBeanDefinition("com.trinclesdar.study.spring.bean.TestBean2");
boolean bean2 = beanDefinitionRegistry.containsBeanDefinition("com.trinclesdar.study.spring.bean.TestBean3");
//如果TestBean2和TestBean3同时存在于我们IOC容器中,那么创建TestBean4类, 加入到容器
//对于我们要注册的bean, 给bean进行封装,
if (bean1 && bean2) {
RootBeanDefinition beanDefinition = new RootBeanDefinition(TestBean4.class);
beanDefinitionRegistry.registerBeanDefinition("com.trinclesdar.study.spring.bean.TestBean4", beanDefinition);
}
}

那么注入容器的组件名称,将会对应变为全路径名。

这种方式,是Spring原生的方式,其底层实现的自带的Bean,就是通过这种方式将Bean注入Spring容器,由于registerBeanDefinitions()方法中,可以提供逻辑处理,因此通过这种方式来完成依赖注入,具备更高的灵活性。

5.总结

通常我们在做日常项目的过程中,最常用的注解为@Bean,@Component,基本上可以满足我们绝大多数的需求,其它几种Bean的注入方式,如ImportSelectorImportBeanDefinitionRegistrar、FacrotyBean等,出场率要低得多,本质上而言,其实最终的实现效果与@Bean实现的效果基本一样。之所以在这里花如此多的篇幅去写Spring的各种Bean的注入方式,一方面是为了更好的了解Sping,二来在工作中,偶尔用这些不太常见的方式来提升一下代码逼格,也是不错的。哈哈!最后,这些知识,在我们了解Spring底层源码实现的道路上,也是很重要的奠基。
最后的最后,附上一张我总结的关于Spring依赖注入的知识点思维导图:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: