手动装配
spring模式注解装配
- 定义:一种用于生命在应用中扮演”组件”角色的注解
- 举例:@Component,@Service,@Configuration等
- 装配: <context:component-scan>或者@ComponentScan
A stereotype annotation is an annotation that is used to declare the role that a component plays within the application. For example, the @Repository annotation in the Spring Framework is a marker for any class that fulfills the role or stereotype of a repository (also known as Data Access Object or DAO).
@Component is a generic stereotype for any Spring-managed component. Any component annotated with @Component is a candidate for component scanning. Similarly, any component annotated with an annotation that is itself meta-annotated with @Component is also a candidate for component scanning. For example, @Service is meta-annotated with @Component .
模式注解是一种用于声明在应用中扮演”组件”角色的注解。如 Spring Framework 中的 @Repository 标注在任何类上 ,用于扮演仓储角色的模式注解。
@Component 作为一种由 Spring 容器托管的通用模式组件,任何被 @Component 标准的组件均为组件扫描的候选对象。类似地,凡是被 @Component 元标注(meta-annotated)的注解,如 @Service ,当任何组件标注它时,也被视作组件扫描的候选对象
Spring Framework 注解 | 场景说明 | 起始版本 |
---|---|---|
@Repository | 数据仓储模式注解 | 2.0 |
@Component | 通用组件模式注解 | 2.5 |
@Service | 服务模式注解 | 2.5 |
@Controller | Web 控制器模式注解 | 2.5 |
@Configuration | 配置类模式注解(代替配置文件进行描述) | 3.0 |
装配方式
<context:component-scan>方式
1
2
3
4
5
6
7
8
9
10
11
12
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring/context.xsd">
<!-- 激活注解驱动特性 -->
<context:annotation-config />
<!-- 找寻被 @Component 或者其派生 Annotation 标记的类(Class),将它们注册为 Spring Bean -->
<context:component-scan base-package="cn.xwmdream.dive.in.spring.boot" />
</beans>@ComponentScan 方式
1
2
3
4"cn.xwmdream.dive.in.spring.boot") (basePackages =
public class SpringConfiguration {
...
}
自定义模式注解
- @Component “派生性”
1
2
3
4
5
6
7({ElementType.TYPE})
(RetentionPolicy.RUNTIME)
public FirstLevelService {
String value() default "";
}
派生性指的是@Component->@Service->@FirstLevelService
派生性不是真的存在,类似class的继承
- @Component “层次性”
1
2
3
4
5
6
7({ElementType.TYPE})
(RetentionPolicy.RUNTIME)
public SecondLevelService {
String value() default "";
}
@Component->@Service->@FirstLevelService->@SecondLevelService
Spring @Enable 模块装配
- 具备相同的功能组件集合,组成所形成一个独立的单元
- 距离:@EnableWebMvc,@EnableAutoConfiguration等
- 实现:注解方式,编程方式
Spring Framework 3.1 开始支持”@Enable 模块驱动”。所谓”模块”是指具备相同领域的功能组件集合, 组合所形成一个独立的单元。比如 Web MVC模块、AspectJ代理模块、Caching(缓存)模块、JMX(Java 管 理扩展)模块、Async(异步处理)模块等。
@Enable注解模块举例
框架实现 | @Enable 注解模块 | 激活模块 |
---|---|---|
Spring Framework | @EnableWebMvc | Web MVC 模块 |
@EnableTransactionManagement | 事务管理模块 | |
@EnableCaching | Caching 模块 | |
@EnableMBeanExport | JMX 模块 | |
@EnableAsync | 异步处理模块 | |
@EnableWebFlux | Web Flux 模块 | |
@EnableAspectJAutoProxy | AspectJ 代理模块 | |
Spring Boot | @EnableAutoConfiguration | 自动装配模块 |
@EnableManagementContext | Actuator 管理模块 | |
@EnableConfigurationProperties | 配置属性绑定模块 | |
@EnableOAuth2Sso | OAuth2 单点登录模块 | |
Spring Cloud | @EnableEurekaServer | Eureka服务器模块 |
@EnableConfigServer | 配置服务器模块 | |
@EnableFeignClients | Feign客户端模块 | |
@EnableZuulProxy | 服务网关 Zuul 模块 | |
@EnableCircuitBreaker | 服务熔断模块 |
实现方式
注解驱动方式
1 |
|
1 | (RetentionPolicy.RUNTIME) |
1 |
|
EnableHelloWorld注解上import了HelloWorldConfiguration类,所以运行EnableHelloWorldBootstrap就可以获取到HelloWorldConfiguration类下的hello的bean能被装配到容器中
接口编程方式
1 | public class HelloWorldImportSelector implements ImportSelector { |
1 | (RetentionPolicy.RUNTIME) |
EnableHelloWorld的import改成了HelloWorldImportSelector,而HelloWorldImportSelector的selectImports返回了HelloWorldConfiguration,所以可以将HelloWorldConfiguration下的bean装配到容器中。注意HelloWorldImportSelector的方法可以返回多个配置类
自定义条件装配
基于配置方式实现 -@Profile
1 | public interface CalculateService { |
- 两个类都实现了CalculateService接口的service,但是@profile不同,调用的时候根据这个参数可以加载不同的对象
1 | "com.example.studyspringboot.service") (scanBasePackages = |
- 可以看到加载上下文的时候指定profiles参数,不同的参数对应不同实现类上@Profile的参数
基于编程方式实现(Condition)
自定义Condition1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18/**
* 系统属性条件判断
*/
public class OnSystemPropertyCondition implements Condition {
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
//获取到ConditionalOnSystemProperty注解的所有的参数
Map<String, Object> attributes = metadata.getAnnotationAttributes(ConditionalOnSystemProperty.class.getName());
//分别获取到name和value属性
String propertyName = String.valueOf(attributes.get("name"));
String propertyValue = String.valueOf(attributes.get("value"));
//获取系统的name属性值
String javaPropertyValue = System.getProperty(propertyName);
//如果相同返回true
return propertyValue.equals(javaPropertyValue);
}
}
自定义注解
1
2
3
4
5
6
7
8(RetentionPolicy.RUNTIME)
({ElementType.TYPE,ElementType.METHOD})
(OnSystemPropertyCondition.class)
public ConditionalOnSystemProperty {
String name();
String value();
}使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14//我使用这台电脑的user.name是hp
"hp",name="user.name") (value=
public String helloWorld(){
return "hello 2019";
}
public static void main(String[] args) {
ConfigurableApplicationContext run = new SpringApplicationBuilder(ConditionalOnSystemPropertyBootStrap.class).web(WebApplicationType.NONE)
.run(args);
String h = run.getBean("helloWorld",String.class);
System.out.println(h);
//关闭上下文
run.close();
}在注解上使用Conditional指定一个Condition,当调用helloWorld的bean时会激活它头上的ConditionalOnSystemProperty注解,这个注解会调用OnSystemPropertyCondition的matches方法,如果true才会加载这个bean
- 我这台电脑的user.name是hp,所以在matches最后返回的值是true
自动装配
实现方式
- 激活自动装配-@EnableAutoConfiguration
- 实现自动装配-xxxAutoConfiguration
- 配置自动装配实现-META-INF/spring.factories
自定义自动装配
- 创建自动装配类
1
2
3
4// spring模式注解
//spring@Enable模块装配
"user.name",value="hp")//条件装配 (name=
public class HelloWorldAutoConfiguration {}
- 在这个类上调用了@Enablehelloworld,使用之前的模块装配将’hello’bean装配进来
- 使用了ConditionalOnSystemProperty进行条件装配
‘HelloWorldAutoConfiguration’
条件判断: user.name == “hp”
模式注解: @Configuration
@Enable 模块: @EnableHelloWorld -> HelloWorldImportSelector -> HelloWorldConfiguration - > hello bean
- 创建(resources)/META-INF/spring.factories,指定自动装配类
1
2
3#自动装配
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.studyspringboot.configuration.HelloWorldAutoConfiguration
- 会将HelloWorldAutoConfiguration装配到容器中
- 运行
1
2
3
4
5
6
7
8
9
10
11
public class EnableAutoConfigurationBootstrap {
public static void main(String[] args) {
ConfigurableApplicationContext context = new SpringApplicationBuilder(EnableAutoConfigurationBootstrap.class).web(WebApplicationType.NONE)
.run(args);
String hello = context.getBean("hello", String.class);
System.out.println(hello);
//关闭上下文
context.close();
}
}
注解EnableAutoConfiguration会将spring.factories的HelloWorldAutoConfiguration类自动装配进来,然后装配@Enablehelloworld所指定的类
只是在springframework手动装配基础上,增加了spring.factories和EnableAutoConfiguration,实现了自动装配
理解SpringApplication
- 定义:Spring应用引导类,提供便利的自定义行为方法
- 场景:嵌入式Web应用和非Web应用
- 运行:SpringApplication#run(String …)
SpringApplication基本使用
SpringApplication运行
1 | SpringApplication.run(xxx.class,args); |
- 将启动Java的参数args传给了SpringApplication
自定义SpringApplication
SpringApplication准备阶段
- 配置:SpringBean源
- 推断:Web应用类型和主引导类(Main Class)
- 加载:应用上下文初始器和应用事件监听器