【IoCDI】_方法注解@Bean
目录
1. 类注解的使用局限
2. 仅使用@Bean注解
3. 五大注解配合使用@Bean
3.1 使用方式1:getBean传参Bean类型
3.2 使用方式2:getBean传参Bean名称
3.3 使用方式3:getBean传参Bean名称+类型
在上文中,已经介绍了五大类注解及getBean方法的使用,详见下文:
【Ioc&DI】_存储Bean的五大类注解及getBean的使用-CSDN博客文章浏览阅读607次,点赞6次,收藏18次。(1) 类注解:@Controller、@Service、@Repository、@Component、@Configuration;在系统中,对于非Controller层、非Service层和非Dao层的其他bean,使用@Component注解实现存储;在上文实现IoC基本存取功能的两个注解中,要把某个对象交给IOC容器管理,需要在类上添加⼀个@Component注解。(@Controller、@Service、@Repository与三层架构分别对应)https://blog.csdn.net/m0_63299495/article/details/145421932?sharetype=blogdetail&sharerId=145421932&sharerefer=PC&sharesource=m0_63299495&spm=1011.2480.3001.8118https://blog.csdn.net/m0_63299495/article/details/145421932?sharetype=blogdetail&sharerId=145421932&sharerefer=PC&sharesource=m0_63299495&spm=1011.2480.3001.8118https://blog.csdn.net/m0_63299495/article/details/145421932?sharetype=blogdetail&sharerId=145421932&sharerefer=PC&sharesource=m0_63299495&spm=1011.2480.3001.8118https://blog.csdn.net/m0_63299495/article/details/145421932?sharetype=blogdetail&sharerId=145421932&sharerefer=PC&sharesource=m0_63299495&spm=1011.2480.3001.8118已经了解到:
Spring提供的注解可分为两大类:
1、类注解:@Controller、@Service、@Repository、@Component、@Configuration;
2、方法注解:@Bean;
基于已经了解的五大类注解的相关知识,现介绍方法注解@Bean。
1. 类注解的使用局限
在上文(见链接)中,已经提到,五大注解只能加在类上。
除此之外,类注解还有2个局限性:
1、五大注解只能加在类上,并且只能加在自己的代码上。
如果引入了一个第三方的Jar包也希望交给Spring管理,则无法加五大注解。
2、通过类注解修饰的bean在Spring容器中仅存储一份。
对于一个类,定义多个对象(如数据库操作定义多个数据源)时,类注解也是无法发挥作用的。
注:对于第2条,可以进行测试:
在Config包下创建一个UserConfig类,在启动类中进行测试:
package com.example.iocdemo1;
import com.example.iocdemo1.Config.UserConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
@SpringBootApplication
public class IoCDemo1Application {
public static void main(String[] args) {
ApplicationContext context=
SpringApplication.run(IoCDemo1Application.class, args);
UserConfig config1 = context.getBean(UserConfig.class);
System.out.println("config1: "+config1);
UserConfig config2=context.getBean(UserConfig.class);
System.out.println("config2: "+config2);
System.out.println("config1 == config2? "+(config1 == config2));
}
}
启动项目查看日志:
可见config1与config2地址相同,本质上是一个对象。可见使用类注解修饰的类,在容器当中仅存储了一份,无论使用getBean取出多少次,取出的都是同一个bean;
2. 仅使用@Bean注解
在Config包下创建一个UserInfo类:
package com.example.iocdemo1.Config;
import lombok.Data;
@Data
public class UserInfo {
private int id;
private String name;
private int age;
}
在同个包下再创建一个BeanConfig类:
package com.example.iocdemo1.Config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
public class BeanConfig {
@Bean
public UserInfo userInfo(){
UserInfo userInfo1=new UserInfo();
userInfo1.setId(1);
userInfo1.setName("zhangsan");
userInfo1.setAge(20);
return userInfo1;
}
@Bean
public UserInfo userInfo2(){
UserInfo userInfo2=new UserInfo();
userInfo2.setId(2);
userInfo2.setName("lisi");
userInfo2.setAge(21);
return userInfo2;
}
}
在运行类中尝试获取UserInfo:
package com.example.iocdemo1;
import com.example.iocdemo1.Config.UserInfo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
@SpringBootApplication
public class IoCDemo1Application {
public static void main(String[] args) {
ApplicationContext context=
SpringApplication.run(IoCDemo1Application.class, args);
UserInfo userInfo = context.getBean(UserInfo.class);
System.out.println(userInfo);
}
}
运行程序,报错如下:
表示未找到类型为UserInfo.class的bean。
3. 五大注解配合使用@Bean
3.1 使用方式1:getBean传参Bean类型
在2.1部分,已完成了在BeanConfig类的方法前使用@Bean注解。
启动程序发现,程序抛异常:NoSuchBeanDefinitionException,这与Spring的扫描机制有关。
Spring通过扫描注解来明确需要管理的bean,但扫描并不全盘扫描方法注解。
对于方法注解@Bean,需要配合使用五大注解才能将对象正确存储到容器中。
在BeanConfig类前增加@Configuration注解:
package com.example.iocdemo1.Config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class BeanConfig {
@Bean
public UserInfo userInfo(){
UserInfo userInfo1=new UserInfo();
userInfo1.setId(1);
userInfo1.setName("zhangsan");
userInfo1.setAge(20);
return userInfo1;
}
@Bean
public UserInfo userInfo2(){
UserInfo userInfo2=new UserInfo();
userInfo2.setId(2);
userInfo2.setName("lisi");
userInfo2.setAge(21);
return userInfo2;
}
}
保持其他类程序不变,重新启动程序:
启动程序发现,程序抛异常:NoUniqueBeanDefinitionException,表示当前扫描到两个bean,一个bean名为userInfo,一个bean名为userInfo2;
再次对应启动类相关代码,当前使用方式中,Spring无法识别bean的原因在于:
以传参为Bean类型调用getBean时,若一个类型存在多个Bean时,就会使得Spring无法确定到底要使用哪个类。
注:关于不同注解方式下的bean的名称:
使用@Bean注解时,bean的名称是方法名;
使用五大注解时,bean的名称是类名的小驼峰表示法,且当类名前两个字母均为大写时,bean名即类名)
3.2 使用方式2:getBean传参Bean名称
针对某类型存在多个Bean时,使用方式1存在的问题,可采用第2种使用方式。
给getBean方法传参Bean的名称,修改启动类程序如下:
package com.example.iocdemo1;
import com.example.iocdemo1.Config.UserInfo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
@SpringBootApplication
public class IoCDemo1Application {
public static void main(String[] args) {
ApplicationContext context=
SpringApplication.run(IoCDemo1Application.class, args);
UserInfo userInfo1 = (UserInfo) context.getBean("userInfo");
System.out.println(userInfo1);
UserInfo userInfo2 = (UserInfo) context.getBean("userInfo2");
System.out.println(userInfo2);
}
}
重新启动程序:
注:对于给getBean方法传参Bean的名称(方式2)需要强制类型转换。
3.3 使用方式3:getBean传参Bean名称+类型
对某类型存在多个Bean,使用方式1存在的问题,除第2种使用方式外,可采用第3种使用方式。
给getBean方法传参Bean的名称+类型,修改启动类程序如下:
package com.example.iocdemo1;
import com.example.iocdemo1.Config.UserInfo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
@SpringBootApplication
public class IoCDemo1Application {
public static void main(String[] args) {
ApplicationContext context=
SpringApplication.run(IoCDemo1Application.class, args);
UserInfo userInfo1=context.getBean("userInfo",UserInfo.class);
System.out.println(userInfo1);
UserInfo userInfo2=context.getBean("userInfo2", UserInfo.class);
System.out.println(userInfo2);
}
}
重新启动程序:
注:相较于给getBean方法传参Bean的名称(方式2),getBean方法传参Bean的名称+类型(方式3)无需强制类型转换;