Spring注解开发之组件注册(二)

2023-11-08

Spring注解开发之组件注册(一)

5.@Import 给容器导入一个组件

给容器中注册组件

一、包扫描 + 组件标注注解(@Controller/@Service/@Repository/@Component) [自己写的类]

二、@Bean [导入的第三包里面的组件]

三、@Import [快速给容器中导入组件] (@Import{Color.class,Red.class})

    1.@Import(要导入到容器中的组件),容器中就会自动注册这个组件,id默认是组件全名

在这里插入图片描述

​ 2. @ImportSelector: 返回需要导入组建的全类名数组

// 自定义逻辑,返回需要导入的组件
public class MyImportSelector implements ImportSelector {
    // 返回值就是要导入到容器中的组件的全类名
    // AnnotationMetadata:当前标注@Import注解类的所有信息
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return new String[]{"com.lv.pojo.Blue", "com.lv.pojo.Yellow"};// 返回的类注入容器
    }
}

​ 3.使用ImportBeanDefinitionRegister 手动注册bean到容器中

public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {

    /**
     * AnnotationMetadata:当前类的注解信息
     * BeanDefinitionRegistry:注册类
     * 把所有需要添加到容器中的bean,调用BeanDefinitionRegistry.registerBeanDefinition手动注册
     */
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        // 查询容器中是否存在red组件
        boolean red = registry.containsBeanDefinition("com.xjhqre.pojo.Red");
        if (red) {
            // 指定bean的定义信息(bean的类型,bean的scope)
            BeanDefinition beanDefinition = new RootBeanDefinition(Purple.class);
            // 第一个参数指定bean的id
            registry.registerBeanDefinition("purple", beanDefinition);
        }
    }
}

四、使用Spring提供的FactoryBean (工厂Bean)

​ 1.默认获取到的是工厂bean调用getObject创建的对象

​ 2.要获取工厂Bean本身,我们需要给id前面加一个& 即 &colorFactoryBean

// 创建一个Spring定义的FactoryBean
public class ColorFactoryBean implements FactoryBean<Color> {

    // 返回一个Color对象,这个对象会添加到容器中
    @Override
    public Color getObject() throws Exception {
        return new Color();
    }

    @Override
    public Class<?> getObjectType() {
        return Color.class;
    }

    // 返回是否为单例,
    // true 单实例  在容器中保存一份
    // false,则每次创建时调用getObject()方法
    @Override
    public boolean isSingleton() {
        return true;
    }
}

在配置类中导入这个组件!!!

@Test
public void test5() {
    AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig4.class);
    String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
    // 工厂bean获取的是调用getObject创建的对象
    Object colorFactoryBean = applicationContext.getBean("colorFactoryBean");
    System.out.println(colorFactoryBean.getClass());

    // 如果想要拿到colorFactoryBean对象,则需要在传入的id前加一个&标识
    Object colorFactoryBean2 = applicationContext.getBean("&colorFactoryBean");
    System.out.println(colorFactoryBean2.getClass());
}

6.Bean生命周期

即bean从创建 ----> 初始化 -----> 销毁的过程

容器管理bean的生命周期;

我们可以自定义初始化和销毁方法,容器在bean进行进行到当前生命周期可以自定义初始化和销毁方法

构造(对象创建)

  • 单实例:在容器启动的时候创建对象
  • 多实例:在每次获取的时候创建对象

初始化

  • 对象完成创建,并赋值好后,调用初始化方法

销毁

  • 单实例:在容器关闭的时候销毁

  • 多实例:容器不会管理这个bean,所以不会调用销毁方法(初始化会在第一次使用这个对象时才会创建)

在这里插入图片描述

初始化和销毁方法:

  1. 通过@Bean注解指定init-method和destroy-method

在这里插入图片描述
在这里插入图片描述

  1. 实现InitializingBean和DisposableBean接口,重写里面的destroy和afterPropertiesSet方法

    1. 通过让bean实现InitializingBean接口来定义初始化逻辑
    2. 通过让bean实现DisposableBean接口来定义销毁逻辑
    3. InitializingBean中有一个方法afterPropertiesSet,该方法在bean创建并赋值后调用
  2. 使用@PostConstruct和@PreDestroy注解

    1. @PostConstruct:在bean创建完成并且属性赋值完成后进行初始化
    2. @PreDestroy:在容器销毁bean之前执行
  3. BeanPostProcessor:接口,bean后置处理器,在bean初始化前后进行一些处理

    1. postProcessBeforeInitialization:在初始化之前执行
    2. postProcessAfterInitialization:在初始化之后执行

BeanPostProcessor执行原理

1.执行populateBean(beanName, mbd, instanceWrapper);给bean进行属性赋值

2.开始initializeBean初始化bean

​ 1.先执行applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);,遍历得到容器中所有的BeanPostProcessor;挨个执行beforeInitialization,一但返回null,跳出for循环,不会执行后面的BeanPostProcessor.postProcessorsBeforeInitialization
​ 2.然后执行invokeInitMethods(beanName, wrappedBean, mbd);执行自定义初始化
​ 3.最后执行applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);

7.@Value 属性赋值

在这里插入图片描述

在这里插入图片描述

8.自动装配

Spring利用依赖注入(DI)完成对IOC容器中各个组件的依赖关系赋值

  1. @Autowired:自动注入
    (1)默认优先按照类型去容器中去找对应的组件: applicationContext.getBean(BookDao.class);如果找到了则进行赋值;
    (2)如果找到了多个相同类型的组件,再将属性的名称作为组件的id去容器中查找applicationContext.getBean(“bookDao”)
    (3)@Qualifier(“bookDao”):使用 @Qualifier 指定需要装配的组件的id,而不是使用属性名
    (4)自动装配默认一定要将属性赋值好,没有就会报错,可以使用@Autowired(required = false);来设置为非必须的
    (5)可以利用@Primary:让Spring在进行自动装配的时候,默认使用首选的bean,也可以继续使用@Qualifier(“bookDao”)来明确指定需要装配的bean的名字

  2. Spring还支持使用**@Resource(JSR250)**和@Inject(JSR330) [Java规范注解]

    1. @Resource 可以和@Autowired一样自动装配功能,默认是按照组件名称进行装配的;没有能支持@primary功能没有支持@Autowired(required = false)

    2. @Inject:需要导入java.inject的包,和@Autowired的功能一样

在这里插入图片描述

  1. @Autowired:Spring定义的 @Resource和@Inject都是java规范的AutowiredAnnotationBeanPostProcessor:解析完成自动装配 以上注解都装配进去了

  2. 方法、构造器位置的自动装配

    1. 放在方法上,@Bean+方法参数:参数从容器中获取 ,默认不写@Autowired在这里插入图片描述

    2. 标在构造器上只有一个有参构造器,这个有参构造器的@Autowired可以省略,其参数位置的组件还是可以自动从容器中获取 默认加在ioc容器中的组件,容器会调用无参构造器创建对象,再进行初始化赋值等操作 在这里插入图片描述

  3. Aware注入Spring底层组件 原理

    1. Aware 接口,提供了类似回调函数的功能
    2. 自定义组件想要使用Spring 容器底层的一些组件(ApplicationContext,BeanFactory);自定义组件需要实现xxxAware接口;在创建对象的时候,会调用接口规定的方法注入相关组件
    3. 原理:通过对应的Processor进行处理的 ApplicationContextAware => ApplicationContextAwareProcessor 后置处理器,在创建完bean后,看见bean实现了相关Aware接口,将组件传进来

9.@Profile环境搭建

Spring我们提供的可以根据当前环境,动态的激活和切换一系列组建的功能

​ 开发、生产、测试环境 数据源的不同

@Profile 指定组件在那个环境的情况下才能被注册到容器中,不指定,任何环境下都能注册这组件
在这里插入图片描述

我们需要在项目的src/main/resources目录下新建一个配置文件,例如dbconfig.properties,在其中写上数据库连接的相关信息,如下所示。

db.user=root
db.password=123456
db.driverClass=com.mysql.jdbc.Driver
import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.EmbeddedValueResolverAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.util.StringValueResolver;

import com.mchange.v2.c3p0.ComboPooledDataSource;

/**
 *
 * @author liayun
 *
 */
@PropertySource("classpath:/dbconfig.properties") // 加载外部的配置文件
@Configuration
public class MainConfigOfProfile implements EmbeddedValueResolverAware {
	
	@Value("${db.user}")
	private String user;
	
	private StringValueResolver valueResolver;
	
	private String dirverClass;
	
	@Bean("testDataSource")
	public DataSource dataSourceTest(@Value("${db.password}") String pwd) throws Exception {
		ComboPooledDataSource dataSource = new ComboPooledDataSource();
		dataSource.setUser(user);
		dataSource.setPassword(pwd);
		dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test");
		dataSource.setDriverClass(dirverClass);
		return dataSource;
	}
	
	@Bean("devDataSource")
	public DataSource dataSourceDev(@Value("${db.password}") String pwd) throws Exception {
		ComboPooledDataSource dataSource = new ComboPooledDataSource();
		dataSource.setUser(user);
		dataSource.setPassword(pwd);
		dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/ssm_crud");
		dataSource.setDriverClass(dirverClass);
		return dataSource;
	}
	
	@Bean("prodDataSource")
	public DataSource dataSourceProd(@Value("${db.password}") String pwd) throws Exception {
		ComboPooledDataSource dataSource = new ComboPooledDataSource();
		dataSource.setUser(user);
		dataSource.setPassword(pwd);
		dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/scw_0515");
		dataSource.setDriverClass(dirverClass);
		return dataSource;
	}

    // 继承EmbeddedValueResolverAware接口
    // 他的实现就是直接用${db.driverClass}获取配置文件的值
	@Override
	public void setEmbeddedValueResolver(StringValueResolver resolver) {
		this.valueResolver = resolver;
		dirverClass = valueResolver.resolveStringValue("${db.driverClass}");
	}

}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Spring注解开发之组件注册(二) 的相关文章

  • 如果在睡眠线程上调用interrupt()会发生什么?

    我有一个线程 然后run I call sleep 如果我中断这个线程会发生什么 MyThread extends Thread public void run try sleep 1000000 catch InterruptedExce
  • 无法使用maven编译java项目

    我正在尝试在 java 16 0 1 上使用 maven 构建 IntelliJ 项目 但它无法编译我的项目 尽管 IntelliJ 能够成功完成 在此之前 我使用maven编译了一个java 15项目 但我决定将所有内容更新到16 0 1
  • 来自数据库的 jfreechart 散点图

    如何使用java中的jfreechart绘制mysql数据库表中数据的散点图 我使用过 Swing 库 任何链接都会有帮助 我搜索了谷歌但找不到理解的解决方案 如果您有代码 请提供给我 实际上我确实做了条形图并使用 jfreechart 绘
  • 在 ContainerRequestFilter 中填充 spring request 作用域 bean

    我使用 jersey 1 13 和 spring 3 1 1 编写了一个在 tomcat 6 上运行的休息服务 在 tomcat 中 我使用一个领域来进行身份验证 在我的应用程序中 我需要当前用户 但我不想从每个资源中的球衣访问Securi
  • Firestore - RecycleView - 图像持有者

    我不知道如何编写图像的支架 我已经设置了 2 个文本 但我不知道图像的支架应该是什么样子 你能帮我告诉我图像的文字应该是什么样子才能正确显示吗 holder artistImage setImageResource model getArt
  • 如果使用的 JVM 是 x86 或 x64,则以不同的方式解决 Maven 依赖关系?

    我设置了一个 Maven 存储库来托管一些 dll 但我需要我的 Maven 项目根据使用的 JVM 是 x86 还是 x64 下载不同的 dll 例如 在运行 x86 版本 JVM 的计算机上 我需要从存储库下载 ABC dll 作为依赖
  • 用于从字段中查找最大值的 MongoTemplate 方法或查询

    我正在使用 MongoTemplate 进行数据库操作 现在我想从所选结果中获取最大字段值 有人可以指导我如何编写查询 以便当我将查询传递给 find 方法时 它将返回我所需的文档最大字段 提前致谢 问候 可以在spring data mo
  • 将表值参数与 SQL Server JDBC 结合使用

    任何人都可以提供一些有关如何将表值参数 TVP 与 SQL Server JDBC 一起使用的指导吗 我使用的是微软提供的6 0版本的SQL Server驱动程序 我已经查看了官方文档 https msdn microsoft com en
  • 列表应该如何转换为具体的实现?

    假设我正在使用一个我不知道源代码的库 它有一个返回列表的方法 如下所示 public List
  • 获取给定类文件的目录路径

    我遇到的代码尝试从类本身的 class 文件所在的同一目录中读取一些配置文件 File configFiles new File this getClass getResource getPath listFiles new Filenam
  • Cloudfoundry:如何组合两个运行时

    cloundfoundry 有没有办法结合两个运行时环境 我正在将 NodeJS 应用程序部署到 IBM Bluemix 现在 我还希望能够执行独立的 jar 文件 但应用程序失败 APP 0 bin sh 1 java not found
  • 逃离的正确方法是什么?使用 Oracle 12c MATCH_RECOGNIZE 时 JDBCPreparedStatement 中的字符?

    以下查询在 Oracle 12c 中是正确的 SELECT FROM dual MATCH RECOGNIZE MEASURES a dummy AS dummy PATTERN a DEFINE a AS 1 1 但它不能通过 JDBC
  • 为什么java中的for-each循环中需要声明变量

    for 每个循环的通常形式是这样的 for Foo bar bars bar doThings 但如果我想保留 bar 直到循环结束 我可以not使用 foreach 循环 Foo bar null Syntax error on toke
  • 将图像添加到自定义 AlertDialog

    我制作了一个 AlertDialog 让用户可以从我显示的 4 个选项中选择一个 前 3 个让他们在单击号码时直接拨打号码 第 4 个显示不同的视图 现在看起来是这样的 由于第四个选项的目的是不同的任务 我想让它看起来不同 因为用户可能会感
  • JVM:是否可以操作帧堆栈?

    假设我需要执行N同一线程中的任务 这些任务有时可能需要来自外部存储的一些值 我事先不知道哪个任务可能需要这样的值以及何时 获取速度要快得多M价值观是一次性的而不是相同的M值在M查询外部存储 注意我不能指望任务本身进行合作 它们只不过是 ja
  • Java的-XX:+UseMembar参数是什么

    我在各种地方 论坛等 看到这个参数 并且常见的答案是它有助于高并发服务器 尽管如此 我还是找不到 sun 的官方文档来解释它的作用 另外 它是Java 6中添加的还是Java 5中存在的 顺便说一句 许多热点虚拟机参数的好地方是这一页 ht
  • Java:多线程内的 XA 事务传播

    我如何使用事务管理器 例如Bitronix http docs codehaus org display BTM Home JBoss TS http www jboss org jbosstm or Atomikos http www a
  • Java &= 运算符应用 & 或 && 吗?

    Assuming boolean a false 我想知道是否这样做 a b 相当于 a a b logical AND a is false hence b is not evaluated 或者另一方面 这意味着 a a b Bitwi
  • 嵌入式 Jetty - 以编程方式添加基于表单的身份验证

    有没有一种方法可以按如下方式以编程方式添加基于表单的身份验证 我用的是我自己的LdapLoginModule 最初我使用基本身份验证并且工作正常 但现在我想在登录页面上进行更多控制 例如显示徽标等 有没有好的样品 我正在使用嵌入式 jett
  • 在哪里存储 Java 的 .properties 文件?

    The Java教程 http download oracle com javase tutorial essential environment properties htmlon using Properties 讨论如何使用 Prop

随机推荐