【SpringBoot:详解Bean装配】

这篇具有很好参考价值的文章主要介绍了【SpringBoot:详解Bean装配】。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

【SpringBoot:详解Bean装配】,java,rpc,开发语言,spring boot,mvc,spring

🏡Java码农探花

 🔥 推荐专栏:<springboot学习>

🛸学无止境,不骄不躁,知行合一


文章目录
  • 前言
  • 一、IoC容器的简介
  • BeanFactory接口源码
  • 二、Bean装配
  • 扫描装配
  • 探索启动类
  • 条件装配
  • 自定义Bean
  • 总结

前言

IoC((Inversion of Control,控制反转)容器是 Spring 的核心,可以说 Spring 是一种基于 IoC容器编程的框架。因为Spring Boot 是基于注解的开发 Spring IoC, 所以我们就从全注解的方式来讲诉Bean装配。


一、IoC容器的简介

Spring IoC 容器是一个管理 Bean 的容器,在 Spring 的定义中,它要求所有的 IoC 容器都需要实现接口 BeanFactory,它是一个顶级容器接口。 我们从源码讲诉。

BeanFactory接口源码

package org.springframework.beans.factory;

import org.springframework.beans.BeansException;
import org.springframework.core.ResolvableType;
import org.springframework.lang.Nullable;

public interface BeanFactory {
	// 前缀
    String FACTORY_BEAN_PREFIX = "&";
	
	// 多个getBean方法
    Object getBean(String name) throws BeansException;

    <T> T getBean(String name, Class<T> requiredType) throws BeansException;

    Object getBean(String name, Object... args) throws BeansException;

    <T> T getBean(Class<T> requiredType) throws BeansException;

    <T> T getBean(Class<T> requiredType, Object... args) throws BeansException;

    <T> ObjectProvider<T> getBeanProvider(Class<T> requiredType);

    <T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType);
	
	// 是否包含Bean
    boolean containsBean(String name);
	
	//是否单例
    boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
	
	// 是否原型
    boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
	
	// 是否类型匹配
    boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;

    boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException;
	
	// 获取Bean的类型
    @Nullable
    Class<?> getType(String name) throws NoSuchBeanDefinitionException;
	
	// 获取Bean的别名
    @Nullable
    Class<?> getType(String name, boolean allowFactoryBeanInit) throws NoSuchBeanDefinitionException;

    String[] getAliases(String name);
}

分析:

  • 上诉源码中加入了中文注释,通过它们就可以理解这些方法的含义。
  • 这里值得注意的是接口中的几个方法:
    • 首先我们看到了多个getBean 方法,这也是IoC 容器最重要的方法之一, 它的意义是从IoC 容器中获取Bean而从多个getBean方法中可以看到有按类型(bytype)获取Bean 的,也有按名称(by name)获取 Bean 的,这就意味着在 Spring IoC 容器中,允许我们按类型或者名称获取 Bean。这对理解后面将讲到的Spring 的依赖注入(Dependency Injection, DI) 是十分重要的。
    • isSingleton 方法则判断 Bean 是否在 Spring IoC 中为单例。这里需要记住的是在 Spring IoC 容器中,默认的情况下, Bean 都是以单例存在的,也就是使用 getBean 方法返回的都是同一个对象。与isSingleton 方法相反的是 isPrototype 方法,如果它返回的是 true,那么当我们使用 getBean 方法获取Bean 的时候, Spring IoC 容器就会创建一个新的 Bean 返回给调用者。

由于BeanFactory 的功能还不够强大,因此 Spring 在 BeanFactory 的基础上, 还设计了一个更为高级的接口 ApplicationContext。 它是 BeanFactory 的子接口之一, 在 Spring 的体系中 BeanFactory 和ApplicationContext 是最为重要的接口设计,在现实中我们使用的大部分 Spring IoC 容器是ApplicationContext 接口的实现类。

【SpringBoot:详解Bean装配】,java,rpc,开发语言,spring boot,mvc,spring

  • 在图中可以看到, ApplicationContext 接口通过继承上级接口,进而继承 BeanFactory 接口, 但是在BeanFactory 的基础上,扩展了消息国际化接口(MessageSource)、环境可配置接口 (EnvironmentCapable)、应用事件发布接口(ApplicationEventPublish巳r) 和资源模式解析接口(ResourcePatternResolver),所以它的功能会更为强大
  • 在Spring Boot 当中我们主要是通过注解来装配Bean到 Spring IoC 容器中,为了贴近 SpringBoot 的需要, 这里不再介绍与 XML 相关的 IoC 容器,而主要介绍一个基于注解的 IoC 容器,它就是AnnotationConfigApplicationContext,从名称就可以看出它是一个基于注解的 IoC 容器。 之所以研究它, 是因为Spring Boot 装配和获取 Bean 的方法与它如出一辙。

例:创建一个User类,然后使用AnnotationConfigApplicationContext构建IoC容器

public class User {
	private Long id; 
	private String userName; 
/**setter and getter **/ 
}
import org.springframework.context.annotation.Bean; 
import org.springframework.context.annotation.Con f工guration ;
import com.springboot.chapter3.po] o.User;
@Configuration 
public class AppConfig { 
	@Bean(name =”user” } 
	public User ini tUser () { 
		User user= new User (); 
		user. set Id (1L) ; 
		user.setUserName (”aa”); 
		return user;
	}
}

@Configuration 代表这是一个 Java 配置文件, Spring 的容器会根据它来生成IoC 容器去装配Bean;@Bean 代表将 initUser 方法返回的 POJO 装配到 IoC 容器中,而其属性name 定义这个 Bean 的名称如果没有配置它,则将方法名称“initUser”作为 Bean 的名称保存到Spring IoC 容器中。

import org.apache. log4j .Logger; 
import org. springframework.context.ApplicationContext; 
import org. springframework.context annotation.AnnotationConfigApplicat工onContext;
import com.springboot.chapter3.po] o .User;
public class IoCTest { 
	private static Logger log= Logger.getLogger(IoCTest.class); 
	publ工c static 飞roid main (String [] args) { 
		ApplicationContext ctx = new AnnotationConfigAppl丰cationContext(AppConfig. class);
 		User user= ctx.getBean(User.class); 
	}
}

代码中将Java 配置文件 AppConfig 传递给 AnnotationConfigApplicationContext 的构造方法,这样它就能够读取配置了。然后将配置里面的Bean装配到IoC容器中,于是可以使用 getBean方法获取对应的POJO。

二、Bean装配

扫描装配

上诉讲诉的User对象装配就是使用@Bean装配。但是如果一个个的 Bean 使用注解@Bean 注入 Spring loC 容器中,那将是一件很麻烦的事情。好在Spring 还允许我们进行扫描装配 Bean 到 loC 容器中,对于扫描装配而言使用的注解是@Component和@ComponentScan@Component 是标明l哪个类被扫描进入 Spring IoC 容器,而ComponentScan则是标明采用何种策略去扫描装配Bean

@Component(”user") 
public class User { 
	@Value("1") 
	private Long id; 
	@Value("aa"} 
	private String userName; 
/**setter and getter **/ 
}

这里的注解@Component表明这个类将被SpringIoC 容器扫描装配,其中配置的“user"则是作为Bean 的名称,当然你也可以不配置这个字符串,那么IoC容器就会把类名第一个字母作为小写其他不变作为Bean 名称放入到IoC 容器中注解@Value则是指定具体的值,使得Spring IoC给予对应的属性注入对应的值。为了让SpringIoC 容器装配这个类, 需要改造类AppConfig:

import org.springframework.context.annotat工on.ComponentScan;
import org.springframework.context.annotation Configuration; 
@Configuration 
@ComponentScan 
public class AppConfig {
}

这里加入了@ComponentScan,意味着它会进行扫描,但是它只会扫描类AppConfig所在的当前包和其子包。也就是@ComponentScan默认扫描当前类所在包及其子包。 所以User类的位置要注意。

测试:

Applicat工onContext ctx = new AnnotationConfigApplicationContext{AppConfig.class) ;
User user= ctx.getBean(User.class); 
log. info(user.getid());

为了更加合理,@ComponentScan还允许我们自定义扫描的包,我们看一下源码:

package org.springframework.context.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.core.annotation.AliasFor;

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
//在一个类中可重复定义
@Repeatable(ComponentScans.class)
public @interface ComponentScan {

	// 定义扫描的包
    @AliasFor("basePackages")
    String[] value() default {};
	
	//定义扫描的包
    @AliasFor("value")
    String[] basePackages() default {};
	
	//定义扫描的类
    Class<?>[] basePackageClasses() default {};
	
	//Bean name生成器
    Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;
	
	//作用域解析器
    Class<? extends ScopeMetadataResolver> scopeResolver() default AnnotationScopeMetadataResolver.class;
	
	//作用域代理模式
    ScopedProxyMode scopedProxy() default ScopedProxyMode.DEFAULT;
	
	//资源匹配模式
    String resourcePattern() default "**/*.class";
	
	//是否启用默认的过滤器
    boolean useDefaultFilters() default true;
	
	//当满足过滤器的条件时扫描
    Filter[] includeFilters() default {};
	
	//当不满足过滤器的条件时扫描
    Filter[] excludeFilters() default {};
	
	//是否延迟初始化
    boolean lazyInit() default false;
	
	//定义过滤器
    @Retention(RetentionPolicy.RUNTIME)
    @Target({})
    public @interface Filter {
   		//过滤器类型,可以按注解类型或者正则式等过滤
        FilterType type() default FilterType.ANNOTATION;
		
		//定义过滤的类
        @AliasFor("classes")
        Class<?>[] value() default {};

        @AliasFor("value")
        Class<?>[] classes() default {};
		
		//匹配方式
        String[] pattern() default {};
    }
}

分析:

  • 首先可以通过配置项basePackages定义扫描的包名,在没有定义的情况下,它只会扫描当前包和其子包下的路径:还可以通过basePackageClasses 定义扫描的类;
  • 其中还有 includeFilters 和 excludeFilters, includeFilters 是定义满足过滤器(Filter)条件的 Bean 才去扫描, excludeFilters 则是排除过滤器条件的 Bean,它们都需要通过一个注解@Filter 去定义,它有一个type 类型,这里可以定义为注解或者正则式等类型。 classes定义注解类, pattern 定义正则式类

所以得出三个扫描路径表示:

@ComponentScan ("com.springboot.example.* ")
@ComponentScan(basePackages = {"com.springboot.example.pojo"})
@ComponentScan(basePackageClasses = {User.class} ) 

以及排除扫描包或类,让其不被装配:

//扫描example下所有包除了@Service装配的类
//这样,由于加入了 excludeFilters 的配置,使标注了@Service 的类将不被 IoC 容器扫描注入,这样就可以把它类排除到 Spring IoC容器中了。
@ComponentScan(basePackages = {"com.dragon.restart"},excludeFilters = {@ComponentScan.Filter(classes = Service.class)})
探索启动类

事实上,之前在 Spring Boot 的注解@SpringBootApplication 也注入了@ComponentScan,这里不妨探索其源码:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
//自定义排除的扫描类
@ComponentScan(
    excludeFilters = {@Filter(
    type = FilterType.CUSTOM,
    classes = {TypeExcludeFilter.class}
), @Filter(
    type = FilterType.CUSTOM,
    classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {
	//通过类型排除自动配置
    @AliasFor(
        annotation = EnableAutoConfiguration.class
    )
    Class<?>[] exclude() default {};
	//通过名称排除自动配置类
    @AliasFor(
        annotation = EnableAutoConfiguration.class
    )
    String[] excludeName() default {};
	//定义扫描包
    @AliasFor(
        annotation = ComponentScan.class,
        attribute = "basePackages"
    )
    String[] scanBasePackages() default {};
	//定义被扫描的类
    @AliasFor(
        annotation = ComponentScan.class,
        attribute = "basePackageClasses"
    )
    Class<?>[] scanBasePackageClasses() default {};

显然,通过它就能够定义扫描哪些包。但是这里需要特别注意的是,它提供的exclude和excludeName两个方法是对于其内部的自动配置类才会生效的。为了能够排除其他类,还可以再加入@ComponentScan以达到我们的目的。

条件装配

  • 例如在数据库连接池的配置中漏掉一些配置会造成数据源不能连接上。 在这样的情况下, IoC容器如果还进行数据源的装配, 则系统将会抛出异常,导致应用无法继续。这时倒是希望IoC容器不去装配数据源。
  • 为了处理这样的场景, Spring 提供了@Conditional注解帮助我们,而它需要配合另外一个接口Condition(org.springframework.context.annotation.Condition )来完成对应的功能。

装配的Bean:

@Bean(name = "dataSource", destroyMethod = "close" ) 
@Conditional(DatabaseConditional.class)
public DataSource getDataSource ( 
@Value("${database.driverName}") String driver, 
@Value("${database.url}") String url, 
@Value("${database.username}") String username, 
@Value("{database.password}") String password 
){ 
	Properties props= new Properties(); 
	props.setProperty("driver", driver); 
	props setProperty("url", url); 
	props.setProperty("username", username); 
	props setProperty("password", password); 
	DataSource dataSource = null; 
	try { 
		dataSource = BasicDataSourceFactory.createDataSource(props) ; 
	) catch (Exception e) { 
		e.printStackTrace();
	}
	return dataSource;
}

自定义DatabaseConditional类:

public class DatabaseConditional implements Condition { 
/**
* 数据库装配条件
* 
* @param context 条件上下文
* @param metadata 注释类型的元数据
* @return true 装配 Bean,否则不装配
*/
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { 
	//取出环境配置
	Environment env = context.getEnvironment(); 
	//判断属性文件是否存在对应的数据库配置
	return env.containsProperty(”database.driverName” ) 
		&& env.containsProperty(”database.url”) 
		&& env.containsProperty(” database.username”) 
		&& env.containsProperty (”database.password");

matches 方法首先读取其上下文环境, 然后判定是否已经配置了对应的数据库信息。这样,当这些都己经配置好后则返回true。这个时候Spring会装配数据库连接池的Bean,否则是不装配的。

自定义Bean

  • 现实的Java 的应用往往需要引入许多来自第三方的包, 并且很有可能希望把第三方包的类对象也放入到Spring IoC 容器中,这时@Bean注解就可以发挥作用了。
  • 例如,要引入一个DBCP数据源,我们先在pom.xml上加入项目所需要DBCP包和数据库MySQL驱动程序的依赖。
<dependency> 
	<groupid>org.apache.commons</groupid> 
	<artifactid>commons-dbcp2</artifactid> 
</dependency> 
<dependency> 
	<groupid>mysql</groupid> 
	<artifactid>mysql-connector-ava</artifactid>
</dependency>

这样 DBCP 和数据库驱动就被加入到了项目中,接着将使用它提供的机制来生成数据源:

@Bean(name = "dataSource") 
@Conditional(DatabaseConditional.class)
public DataSource getDataSource (){ 
	Properties props= new Properties(); 
	props.setProperty("driver", driver); 
	props setProperty("url", url); 
	props.setProperty("username", username); 
	props setProperty("password", password); 
	DataSource dataSource = null; 
	try { 
		dataSource = BasicDataSourceFactory.createDataSource(props) ; 
	) catch (Exception e) { 
		e.printStackTrace();
	}
	return dataSource;
}

这里通过@Bean 定义了其配置项 name 为“dataSource“,那么 Spring 就会把它返回的对象用名称“dataSource” 保存在 loC 容器中。当然, 你也可以不填写这个名称,那么它就会用你的方法名称作为Bean 名称保存到 IoC 容器中。通过这样,就可以将第三方包的类装配到SpringIoC容器中了。


总结

以上就是SpringBoot的Bean装配的详细讲解。文章来源地址https://www.toymoban.com/news/detail-855619.html

到了这里,关于【SpringBoot:详解Bean装配】的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • springboot配置使用redis序列化时报错“无法自动装配。找不到 ‘RedisConnectionFactory‘ 类型的 Bean”

    今天在使用springboot操作redis时出现乱码的问题 像这样,这里对应的key明实际上时springboot:string 对应的值时徐浩的redis 但是当向redis推送数据时就乱码了,后面一查是因为在springboot-redis中,默认配置没有序列化,直接将string转成了byte 所以需要配置一下序列化 我这里配置了一下

    2024年02月07日
    浏览(39)
  • JavaWeb开发06-原理-Spring配置优先级-Bean管理-SpringBoot原理-Maven继承和聚合-私服

    不同配置文件,配置同一个属性谁有效 propertiesymlyaml 命令行参数Java系统属性 项目打包后要改变属性: 红色是Java系统属性,绿色是命令行参数 ‘ 获取IOC容器:applicationContext就是IOC容器对象 IOC容器中bean是默认单例的只有一个,这样三个获取的bean是同一个 单例还是多例取决

    2024年04月23日
    浏览(45)
  • 【Spring教程11】Spring框架实战:IOC/DI注解开发管理第三方bean的全面深入详解

    欢迎大家回到《 Java教程之Spring30天快速入门》,本教程所有示例均基于Maven实现,如果您对Maven还很陌生,请移步本人的博文《 如何在windows11下安装Maven并配置以及 IDEA配置Maven环境》,本文的上一篇为《 纯注解开发模式下的依赖注入和读取properties配置文件》 前面定义bean的时

    2024年02月04日
    浏览(59)
  • 【Spring】深究SpringBoot自动装配原理

    早期的 Spring 项目需要添加需要配置繁琐的 xml ,比如 MVC 、事务、数据库连接等繁琐的配置。 Spring Boot 的出现就无需这些繁琐的配置,因为 Spring Boot 基于 约定大于配置 的理念,在项目启动时候,将约定的配置类自动装配到 IOC 容器里。 这些都因为 Spring Boot 有自动装配的特性

    2024年02月14日
    浏览(39)
  • Springboot自动装配:三个注解、Selector、spring.factories文件、@ConditionalOnProperty注解

    借鉴: 这个链接是包含run方法进来debug看整个过程的,建议先看:https://www.cnblogs.com/starsray/p/15580915.html https://blog.csdn.net/fengxiandada/article/details/130080828 1.创建springboot应用 如何创建一个spring boot应用?这就很简单了,可以使用idea自带的spring initializr帮助我们选择相应的场景启动

    2024年01月22日
    浏览(42)
  • 拆解Spring boot:Springboot为什么如此丝滑而简单?源码剖析解读自动装配

    🎉🎉欢迎光临,终于等到你啦🎉🎉 🏅我是苏泽,一位对技术充满热情的探索者和分享者。🚀🚀 🌟持续更新的专栏 《Spring 狂野之旅:从入门到入魔》 🚀 本专栏带你从Spring入门到入魔   这是苏泽的个人主页可以看到我其他的内容哦👇👇 努力的苏泽 http://suzee.blog.csdn

    2024年03月23日
    浏览(42)
  • JAVA:Springboot动态装配Druid多数据源

    1、简介 最近打算搭建一个鉴权中心服务,采用springboot+FastMybatis装配Druid,考虑后续拓展采用Druid多数据源配置,以一个数据源为主,多个动态数据源为辅的结构。除了数据库,后续会结合shiro安全框架来搭建。 2、引用 在pom.xml添加框架Springboot +FastMybatis + Druid相关maven引用。

    2024年02月09日
    浏览(45)
  • 【Spring Boot自动装配原理详解与常见面试题】—— 每天一点小知识

                                                                  💧 S p r i n g B o o t 自动装配原理详解与常见面试题 color{#FF1493}{Spring Boot自动装配原理详解与常见面试题} Sp r in g B oo t 自动装配原理详解与常见面试题 💧           🌷 仰望天空

    2024年02月16日
    浏览(43)
  • 基于Xml方式Bean的配置-Bean的依赖注入以及·自动装配

    Bean的依赖注入方式 注入方式 配置方式 通过Bean的set方法注入 通过构造Bean的方法进行注入 其中,ref是reference的缩写形式,翻译为:涉及,参考的意思,用于引用其它Bean的id,value用于指定属性值 注入数据类型 普通数据类型:String、int、boolean,通过value属性指定 引用数据类型

    2024年02月07日
    浏览(51)
  • Spring中的bean标签详解

    用于配置对象交由Spring 来创建。 默认情况下它调用的是类中的无参构造函数,如果没有无参构造函数则不能创建成功。 基本属性: id :Bean实例在Spring容器中的唯一标识 class :Bean的全限定名称 scope :指对象的作用范围,取值如下: 取值范围 说明 singleton 默认值,单例的 p

    2024年02月08日
    浏览(28)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包