Bean相关注解的装配和解析
在日常开发中,项目中大量的Bean的装配。今天就来聊聊如何使用注解装配Bean。这里与其说是SpringBoot装配Bean还是不如说是Spring注解来装配Bean。
装配Bean的方式主要有以下两种方式:
通过Java配置文件@Bean的方式来定义Bean
通过注解扫描的方式@Component和@ComponentScan
一、使用@Bean的方式
首先写一个非常普通的实体类MyBean
public class MyBean {
public String getName() {
return “使用@Bean方式”;
}
}
然后定义一个MyBeanConfig类,在类上添加注解@Configuration,
@Configuration该注解代表是一个 Java 配置文件 , Spring会根据它来生成 IoC 容器去装配 Bean。
@Bean 代表将 configBean方法返回的 POJO 装配到 IoC 容器中, name为Bean 的名称,如果没有配置它,则会将方法名称作为 Bean 的名称保存到 Spring IoC 容器中 。这里方法名称myBean就是MyBean保存在Spring IoC 容器中饿名称,如果在使用名称注入的时候就得使用myBean。否则会报错。
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyBeanConfig {
@Bean
public MyBean configBean() {
return new MyBean();
}
}
看看@Bean源码会发现,其实除了上面说的方法名称作为Bean在Spring IOC 容器中的Bean名称外,还可以使用@Beam(“configBean”)的方式。
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Bean {
@AliasFor(“name”)
String[] value() default {};
@AliasFor("value")
String[] name() default {};
//...省略
}
下面我们创建一个测试controller。
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@RestController
public class MyController {
@Resource(name = “configBean”)
private MyBean configBean;
@GetMapping("/test/bean")
public String test(){
return configBean.getName();
}
}
启动类
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
启动项目
测试工具使用IDEA的工具类里
访问:http://localhost:8080/test/bean
成功搞定。
用上面说的另外一种方式定义Beande 名称
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyBeanConfig {
@Bean(“helloBean”)
public MyBean configBean() {
return new MyBean();
}
}
其他不动,再次启动启动类,就会报异常
所以得注入时候使用Bean名称也得跟着改(按照类型注入得另说,这里是演示Bean在Spring IOC中的名称)。
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@RestController
public class MyController {
//这里把bean在Spring IOC中的名称修改成上面定义的helloBean名称
@Resource(name = “helloBean”)
private MyBean helloBean;
@GetMapping("/test/bean")
public String test(){
return helloBean.getName();
}
}
正常启动
访问也正常
ok,使用@Bean的方式就这样轻松搞定。
二、使用@Component方式
创建一个类MyComponentBean
import org.springframework.stereotype.Component;
@Component
public class MyComponentBean {
public String getName(){
return "使用@Component注解方式";
}
}
一样的,写一个controller类来测试,MyComponentController
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@RestController
public class MyComponentController {
@Resource
private MyComponentBean myComponentBean;
@GetMapping("/test/component")
public String test(){
return myComponentBean.getName();
}
}
启动启动类main方法(和上面一样)。然后访问返回
成功。注解@Component 表明这个类将被Spring IoC容器扫描装配,bean的名称为componentBean。如果不配置这个值 ,那IoC 容器就会把类名第一个字母作为小写,其他的不变作为 Bean 名称放入到 IoC 容器中。
在工作中,controller里我们通常会注入各种service类。比如:UserInfoService、OrderService等。这些service上基本上都会使用@Service,在service层又会注入各种Repository、Mapper、Dao等,然后这些类上基本都添加了注解@Repository来装配Bean。
进入org.springframework.stereotype目录下会发现
其实@Controllert、@Service、@Repository注解上都添加了注解@Component
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Controller {
@AliasFor(
annotation = Component.class
)
String value() default “”;
}
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Service {
@AliasFor(
annotation = Component.class
)
String value() default “”;
}
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Repository {
@AliasFor(
annotation = Component.class
)
String value() default “”;
}
也就是说,除了@Component注解以外,还可以使用上面这三个注解装配Bean。
@Controller 控制器(注入服务)
@Service 服务(注入dao)
@Repository dao(实现dao访问)
@Component (把普通pojo实例化到spring容器中,相当于配置文件中的
)
OK,使用@Component的方式就这样轻松搞定。
三、使用@ComponentScan方式
@ComponentScan是Spring的包扫描组件,作用在配置类上。使用方式为:
@ComponentScan(value=“com.example.demo”)
其常用属性介绍:
value:代表需要扫描的包,扫描包下的有注解@Controller、@Service、@Repository、@Component注解标注的类,将其注入IOC容器。
excludeFilters :是一个 Filter[]数组,作用是排除不需要扫描的包或者类。Filter[]数组里面需要@Filter指定过滤规则,@Filter的type属性表示过滤的规则;@Filter的classes属性是个数组,里面包含需要过滤的类。
includeFilters :是一个 Filter[]数组,作用是指定扫描的时候只需要包含哪些组件。用法与excludeFilters相同
useDefaultFilters:默认过滤规则选项,false时,可以自定义过滤规则
使用场景很多,比如说上文提到的启动类中的SpringBootApplication注解中就使用到了。
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
//使用@ComponentScan
@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 {};
}
ok,今天就分析到这里。