Spring中@Bean注解的作用以及如何使用

Spring中@Bean注解的作用以及如何使用

一、Bean是啥

1、Java面向对象,对象有方法和属性,那么就需要对象实例来调用方法和属性(即实例化); 

2、凡是有方法或属性的类都需要实例化,这样才能具象化去使用这些方法和属性; 

3、规律:凡是子类及带有方法或属性的类都要加上注册Bean到Spring IoC的注解; 

4、把Bean理解为类的代理或代言人(实际上确实是通过反射、代理来实现的),这样它就能代表类拥有该拥有的东西了 

5、我们都在微博上@过某某,对方会优先看到这条信息,并给你反馈,那么在Spring中,你标识一个@符号,那么Spring就会来看看,并且从这里拿到一个Bean或者给出一个Bean

二、注解分为两类:

1、一类是使用Bean,即是把已经在xml文件中配置好的Bean拿来用,完成属性、方法的组装;比如@Autowired , @Resource,可以通过byTYPE(@Autowired)、byNAME(@Resource)的方式获取Bean; 

2、一类是注册Bean,@Component , @Repository , @ Controller , @Service , @Configration这些注解都是把你要实例化的对象转化成一个Bean,放在IoC容器中,等你要用的时候,它会和上面的@Autowired , @Resource配合到一起,把对象、属性、方法完美组装。

两种方式的区别:

  • @Component注解作用于类上,而@Bean注解作用于配置类中的某一个方法上;
  • @Component表明告知Spring为当前的这个类创建一个bean,而@Bean表明告知Spring此方法将会返回一个对象,将返回的对象注入到容器中。
  • @Bean注解的使用更加灵活。

如何使用?

在没有了解@Bean注解之前,相信大家都是以这种方式创建对象的:

    @AllArgsConstructor
    @NoArgsConstructor
    @Component
    public class User {
        private String name;
        private Integer age;
    }

然后直接通过@Autowired从容器中取出该对象

    @Autowired
    private User user

同样的场景,来使用@Bean试试。 

    @Configuration
    public class MyConfiguration {
        @Bean
        public User user() {
            return new User();
        }
    }

该注解必须要在标有@Configuration的配置类中使用才会有效。
上述代码表示,将@Bean注解修饰的方法的返回值注入到IOC容器中。

    @Autowired
    private User user

通过上述几段代码,你可能很难发现@Bean注解灵活在哪里,反而还要作用在配置类中,更麻烦!

使用场景

场景1: 有时候我们需要根据条件来注入组件。

    @Configuration
    public class MyConfiguration {
        @Bean
        public User user() {
            int i = 10;
            if(i < 7) {
                return new User("jack", 20);
              } else {
                  return new User("david", 18);
              }
        }
    }

场景2: 想象一下如果我们需要使用外部引入的lib中的组件时怎么办?使用@Component注解标注到别人的源码上面?显然这是不现实的,这个时候@Bean就可以发挥其优势了。

    @Configuration
    public class MyConfiguration {
        @Bean
        public ArrayList<User> list() {
            ArrayList<User> list = new ArrayList<>();
            list.add(new User("nacy", 17));
            return list;
        }
    }

使用@Bean注解在实际项目中解决的问题

在微服务的两个模块,其中模块A作为公共模块,模块B(SpringBoot模块)导入了模块A的Maven依赖(dependency),在项目运行时只启动模块B,模块A相当于一个静态的公共模块,不会去使用SpringBoot启动它。

模块A:

  • 配置类:
@Configuration
@EnableWebSecurity  // 开启Security
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private EmployeeRolePath employeeRolePath;
    
    @Override
    protected void configure(HttpSecurity http) throws Exception {
         List<String> uri = employeeRolePath.getUri();
    }
  • EmployeeRolePath:
    @Component
    @ConfigurationProperties("role.employee.path")
    public class EmployeeRolePath {
    
        private List<String> uri;
    
        public List<String> getUri() {
            return uri;
        }
    
        public void setUri(List<String> uri) {
            this.uri = uri;
        }
    }

模块B:

  • 配置类,继承了模块A的配置类
    @Configuration
    @EnableWebSecurity  // 开启Security
    public class SecurityConfig extends WebSecurityConfig {
            // ........
            // .........
    }
  • yml配置文件:
role:
  admin:  # 需要admin权限的访问路径
      path:
        uri:
          - /admin/adminRole/**
  employee: # 需要employee权限的访问路径
      path:
        uri:
          - /admin/category/**
          - /admin/dish/**
          - /admin/flavor/**
          - /admin/setmeal/**

先说一下我要实现的功能:要使上述yaml配置文件中的配置成功绑定到EmployeeRolePath类中并生效。

很显然,上述代码肯定不会生效,原因就是我们启动模块B时,Spring只能够扫描到本模块中的配置类SecurityConfig,以及它继承模块A中的配置类WebSecurityConfig,而作用在EmployeeRolePath类上的注解是不可能为生效的,原因就是模块A根本没启动,没有人去扫描他,它只是一个静态的模块而已。

解决:

在模块A的配置类中使用@Bean注解注入EmployeeRolePath组件

    @Configuration
    @EnableWebSecurity  // 开启Security
    public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
        @Override
        protected void configure(HttpSecurity http) throws Exception {
             List<String> uri = employeeRolePath().getUri();
        }
        
        @Bean
        public EmployeeRolePath employeeRolePath() {
            return new EmployeeRolePath();
    }

如上述在本配置类中要使用该组件,直接调用employeeRolePath()就能获取到容器中的EmployeeRolePath组件了。

为什么这样可以生效?
上述说了,当模块B启动时,会先初始化加载模块B的配置类,而模块B的配置类又继承了模块A的配置类,所以Spring是能够扫描到模块A中的配置的,并且它们是在同一个IOC容器中的,所以在模块B中定义的配置文件也会生效。

 

posted @ 2023-05-07 19:09  爵岚  阅读(2173)  评论(0编辑  收藏  举报