当前位置: 首页 > news >正文

【Spring】IoC详解:方法Bean的存储、Bean重命名、扫描路径@Component(下)

1.方法Bean的存储

1.1 方法Bean介绍

类注解是添加到某个类上的, 但是存在两个问题:
1.使用外部包⾥的类, 没办法添加类注解
2.一个类, 需要多个对象, ⽐如多个数据源这种场景, 我们就需要使用方法注解

相比类注解(@Component等)定义对象的身份,方法注解更像“操作指令”,告诉容器如何处理方法或其返回值。

@Bean Spring中最核心的方法注解,通常用在@Configuration标记的配置类中。它的作用是告诉IoC容器:“这个方法的返回值是一个Bean,请帮我管理它。”

1.2 示例

1.2.1 错误1:方法注解没和类注解一起用

创建一个UserInfo类:

@Data
public class UserInfo {
    private int id;
    private String name;
    private int age;
    
}

创建BeanConfig类,把类中的方法放进容器中:

public class BeanConfig {

    @Bean
    public UserInfo userInfo1(){
        UserInfo userInfo = new UserInfo();
        userInfo.setId(1);
        userInfo.setName("liming");
        userInfo.setAge(18);

        return userInfo;
    }

    @Bean
    public UserInfo userInfo2(){
        UserInfo userInfo =new UserInfo();
        userInfo.setId(2);
        userInfo.setName("张三");
        userInfo.setAge(20);

        return userInfo;
    }
}

从容器中取出Bean:

@SpringBootApplication
public class Test1Application {
    public static void main(String[] args) {

        // 获取上下文
        ApplicationContext context = SpringApplication.run(Test1Application.class, args);

        //获取userInfo1
        UserInfo userInfo1 = (UserInfo)context.getBean("userInfo1");
        System.out.println(userInfo1);

        //获取userInfo2
        UserInfo userInfo2 = (UserInfo)context.getBean("userInfo2");
        System.out.println(userInfo2);
    }

}

运行结果:
在这里插入图片描述
原因:
方法注解要和类注解一起使用,否则方法无法放到容器中

修改后的代码:

@Configuration
public class BeanConfig {

    @Bean
    public UserInfo userInfo1(){
        UserInfo userInfo = new UserInfo();
        userInfo.setId(1);
        userInfo.setName("liming");
        userInfo.setAge(18);

        return userInfo;
    }

    @Bean
    public UserInfo userInfo2(){
        UserInfo userInfo =new UserInfo();
        userInfo.setId(2);
        userInfo.setName("张三");
        userInfo.setAge(20);

        return userInfo;
    }
}

运行结果:
在这里插入图片描述

1.2.2 错误2:没有设置可以传参的Bean

上面写的方法Bean中的userInfo是固定的,怎么设置可以变动的userInfo呢?

在方法中加入参数:

@Configuration
public class BeanConfig {

    @Bean
    public UserInfo userInfo1(String name){
        UserInfo userInfo = new UserInfo();
        userInfo.setId(1);
        userInfo.setName(name);
        userInfo.setAge(18);

        return userInfo;
    }

}

获取userInfo1的Bean:

@SpringBootApplication
public class Test1Application {
    public static void main(String[] args) {

        // 获取上下文
        ApplicationContext context = SpringApplication.run(Test1Application.class, args);

        //获取userInfo1
        UserInfo userInfo1 = (UserInfo)context.getBean("userInfo1");
        System.out.println(userInfo1);
    }

}

运行结果:
在这里插入图片描述

在BeanConfig类中添加一个Bean方法,修改后:

@Configuration
public class BeanConfig {

    @Bean //添加一个返回String类型的Bean
    public String name(){
        return "liming";
    }

    @Bean
    public UserInfo userInfo1(String name){
        UserInfo userInfo = new UserInfo();
        userInfo.setId(1);
        userInfo.setName(name);
        userInfo.setAge(18);

        return userInfo;
    }
}

运行结果:
在这里插入图片描述

我们可以发现,上面的name方法的名字和userInfo(String name)中的name一样,如果再创建一个返回String类型的Bean呢?会发生什么呢?

@Configuration
public class BeanConfig {

    @Bean
    public String name(){
        return "liming";
    }

    @Bean
    public String name2(){
        return "zhangsan";
    }

    @Bean
    public UserInfo userInfo1(String name){
        UserInfo userInfo = new UserInfo();
        userInfo.setId(1);
        userInfo.setName(name);
        userInfo.setAge(18);

        return userInfo;
    }
}

运行结果:
在这里插入图片描述

userInfo(String name)中的参数name的匹配是不是与上面方法name()、name2()的上下顺序有关呢?

把name()和name2()位置变换:

@Configuration
public class BeanConfig {

	@Bean
    public String name2(){
        return "zhangsan";
    }

    @Bean
    public String name(){
        return "liming";
    }

    @Bean
    public UserInfo userInfo1(String name){
        UserInfo userInfo = new UserInfo();
        userInfo.setId(1);
        userInfo.setName(name);
        userInfo.setAge(18);

        return userInfo;
    }
}

运行结果:
在这里插入图片描述

把name()方法去掉,留下name2()方法:

@Configuration
public class BeanConfig {

	@Bean
    public String name2(){
        return "zhangsan";
    }

    @Bean
    public String name(){
        return "liming";
    }

    @Bean
    public UserInfo userInfo1(String name){
        UserInfo userInfo = new UserInfo();
        userInfo.setId(1);
        userInfo.setName(name);
        userInfo.setAge(18);

        return userInfo;
    }
}

运行结果:
在这里插入图片描述

1.2.3错误3:多个名字不一样的Bean传参

把返回String类型的Bean存入容器:

@Configuration
public class BeanConfig {

    @Bean
    public String name3(){
        return "liming";
    }

    @Bean
    public String name2(){
        return "zhangsan";
    }

    @Bean
    public UserInfo userInfo1(String name){
        UserInfo userInfo = new UserInfo();
        userInfo.setId(1);
        userInfo.setName(name);
        userInfo.setAge(18);

        return userInfo;
    }

}

获取userInfo1的Bean:

@SpringBootApplication
public class Test1Application {
    public static void main(String[] args) {

        // 获取上下文
        ApplicationContext context = SpringApplication.run(Test1Application.class, args);

        //获取userInfo1
        UserInfo userInfo1 = (UserInfo)context.getBean("userInfo1");
        System.out.println(userInfo1);
    }

}

运行结果:
在这里插入图片描述
可以发现,方法Bean的名称就是方法名。

需要约定传参(注入):

@Configuration
public class BeanConfig {

    @Bean
    public String name3(){
        return "liming";
    }

    @Bean
    public String name2(){
        return "zhangsan";
    }
    
    @Bean
    public UserInfo userInfo1( @Qualifier("name3") String name){
        UserInfo userInfo = new UserInfo();
        userInfo.setId(1);
        userInfo.setName(name);
        userInfo.setAge(18);

        return userInfo;
    }
}

1.2.4总结

总结:
(1)方法Bean注解要和类Bean注解一起使用
(2)方法Bean需要传参时要设置可以传参的方法Bean
(3)传参时优先传参参数名和Bean名字一样的
(4)如果没有名字一样但是类型有多个的Bean,需要约定哪个Bean传参(注入)。

2.Bean重命名

可以通过设置 name 属性给 Bean 对象进⾏重命名操作,如下代码所示:

@Configuration
public class BeanConfig {

    @Bean
    public String name1(){
        return "liming";
    }
    
    //下面三种方法都可以使用
    //@Bean({"u1","userInfo1"})
    //@Bean("u1")
    @Bean(name={"u1","userInfo1"})//起别名u1
    public UserInfo userInfo1( @Qualifier("name1") String name){
        UserInfo userInfo = new UserInfo();
        userInfo.setId(1);
        userInfo.setName(name);
        userInfo.setAge(18);

        return userInfo;
    }

    
}

在容器中取名字为userInfo1u1的Bean

@SpringBootApplication
public class Test1Application {
    public static void main(String[] args) {

        // 获取上下文
        ApplicationContext context = SpringApplication.run(Test1Application.class, args);

        //获取userInfo1
        UserInfo userInfo1 = (UserInfo)context.getBean("userInfo1");
        System.out.println(userInfo1);

        //获取userInfo1
        UserInfo u1 = (UserInfo)context.getBean("u1");
        System.out.println(u1);
    }

}

运行后的结果:
在这里插入图片描述

结论:给Bean起别名后,Bean的新名字和旧名字都可以使用。

3.扫描路径

3.1示例

使用前面学习的四个注解声明的bean,⼀定会⽣效吗?
答: 不⼀定(原因:bean想要⽣效,还需要被Spring扫描)

下面是启动类默认的路径:
在这里插入图片描述
运行时,可以正常启动。

下⾯我们通过修改项⽬⼯程的⽬录结构,来测试bean对象是否⽣效:
在这里插入图片描述
再次运行,发生报错:
在这里插入图片描述
为什么呢?

3.2 @ComponentScan注解

使⽤五⼤注解声明的bean,要想⽣效, 还需要配置扫描路径, 让Spring扫描到这些注解

也就是通过@ComponentScan来配置扫描路径.

@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 {
	......
}

@ComponentScan()中的意思是:
默认会扫描主类所在包及其子包下的所有 @Component,但 Spring Boot 的自动配置类(如 spring-boot-autoconfigure 包下的类)不应该被直接扫描注册,因为它们由 @EnableAutoConfiguration 按需加载

但是我们也可以自定义设置扫描路径:
启动类放的位置:
在这里插入图片描述
启动类代码:

@ComponentScan("org.example.test1")//扫描的包
@SpringBootApplication
public class Test1Application {
    public static void main(String[] args) {

        // 获取上下文
        ApplicationContext context = SpringApplication.run(Test1Application.class, args);

        //获取userInfo1
        UserInfo userInfo1 = (UserInfo)context.getBean("userInfo1");
        System.out.println(userInfo1);

        //获取userInfo1
        UserInfo u1 = (UserInfo)context.getBean("u1");
        System.out.println(u1);
    }

}

运行后,结果:
在这里插入图片描述

相关文章:

  • 计算机操作系统——存储器管理
  • Android 日志输出模块
  • 现在AI大模型能帮做数据分析吗?
  • ScholarCopilot:“学术副驾驶“
  • 【数据结构】励志大厂版·初阶(复习+刷题):复杂度
  • SpringBoot条件注解全解析:核心作用与使用场景详解
  • STM32 HAL库 ADC+TIM+DMA 3路 1S采样一次电压
  • C++对象池设计:从高频`new/delete`到性能飞跃的工业级解决方案
  • pycharm中调试功能讲解
  • PGAdmin下载、安装、基础使用
  • Oracle OCP知识点详解3:使用 vim 编辑文件
  • Web 前端技术解析:构建高效、动态的用户体验
  • qt中,父类中有Q_OBJECT,子类中还需要加Q_OBJECT吗
  • Shell的运行原理以及Linux当中权限问题
  • Flutter 文本组件深度剖析:从基础到高级应用
  • TGCTF web
  • SQL刷题日志(day1)
  • 狂神SQL学习笔记二:安装MySQL
  • DeepSeek AI大模型:中国智能时代的“争气机“-AI生成
  • Python实例题:Python自动获取小说工具
  • 俄宣布停火三天,外交部:希望各方继续通过对话谈判解决危机
  • 庆祝中华全国总工会成立100周年暨全国劳动模范和先进工作者表彰大会隆重举行,习近平发表重要讲话
  • 朝鲜派兵库尔斯克是否有助于解决乌克兰危机?外交部回应
  • 坤莹·帕塔玛·利斯达特拉任世界羽联主席
  • 委员呼吁提高政府机构电话号码准确性,辽宁阜新回应
  • 航天科技集团质量技术部部长严泽想升任集团副总经理