第二章:走向自动装配
第一节:Spring Framework 手动装配
第二节:Spring Framework 手动装配自定义模式注解
spirng 模式注解装配
定义
- 一种用于声明在应用(Spring 或Spring boot中)中扮演“组件”角色的注解
举例
-
@Component
@Service
@Controller
@Configuration
1.@Service @Controller @Repository这三个注解从源码上看其实都是@Component 实现的,所以本质上这三个没有什么区别。
通常地,@Service @Controller @Repository是为了给不同的类打上不同的标志来区别开各个类的作用是什么,
@Service表明是一个服务
@Controller表明是一个控制器
@Repository表明是一个仓储,说明是数据库访问模型
如果该类没有明确定义是服务、控制器、仓储,可以用@Component标明
@Component 作为spring容器托管的通用模式组件,任何被它附加的组件,都会被容器作为组件扫描对象
2.@Autowired
首先spring是一个约定大于配置的框架,变量的名字对于注入的对象是有影响的
@Autowired
private Book book;
其次需要注意的是接口不可以用@Component,也没有意义,提到的bean都是具体的class类
① @Autowired优先按bytype查找并实例化,没有找到任何一个bean,会报错
② 按bytype找到多个,会按byname找,如果仍没找到,会报错(byname查找方式可以用@Qualifier,@Qualifier声明的byname变量优先级最高)
③ 在成员变量注入和setter注入的时候必须加上@Autowired,在构造器注入的时候可以不加,直接按原来的方式写构造器把实例当参数传进去即可,spring官方推荐构造函数注入或setter注入,因为两种是对public做注入
3.@Configuration
是在spring3.0里加入的新特性,通常在写框架的时候被用到,是配置类注解,用来解决变化的问题,很重要
@Configuration主要是用来取代xml配置方式的
装配方式
<context:component-scan>
<beans>
激活注解驱动特性
<context:annotation-config />
寻找被@Component 或者派生注解标记的类class,将他们注册为 spring bean
<context:component-scan base-package="com.lc.springboot" />
</beans>
@ComponentScan
@ComponentScan(basePackages = "com.lc.springboot")
public class SpringConfiguration{
...
}
第三节:@Enable 模块装配两种方式
定义
- 具备相同领域的功能组件集合,组合所形成一个独立的单元
举例
@EnableWebMvc
-web MVC模块@EnableAutoConfiguration
- 自动装配模块@EnableEurekaServer
- Eureka 服务器模块
实现
注解驱动方式
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc{
}
@Configuration
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport{
}
接口编程方式
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(CachingConfigurationSelector.class)
public @interface EnableCaching{
}
public class CachingConfigurationSelector extends AdviceModeImportSelector<EnableCaching>{
switch(adviceMode){
case PROXY:
return new String[]{AutoProxyRegistrar.class.getName(),ProxyCachingConfiguration.class.getName()};
case ASPECTJ:
return new String[]{AnnotationConfigUtils.CACHE_ASPECT_CONFIGURATION_CLASS_NAME};
default:
return null;
}
}
public class AdviceModeImportSelector implements ImportSelector{
}
第四节:Spring条件装配
定义
- Bean装配的前置判断(条件装配也属于spring framework 手动装配一种)
举例
-
@Profile
- 配置化条件装配 -
@Contitional
- 编程条件装配
实现
- 基于配置方式实现 -
@Profile
- 计算服务,多整数求和Sum
-
@Profile("java7")
for循环 -
@Profile("java8")
lambda表达式
public interface Calculate {
//变量参数
Integer sum(Integer... values);
}
@Profile("java7")
@Service
public class Java7Calculate implements Calculate {
public Integer sum(Integer... values) {
System.out.println("java7");
int sum = 0;
for (Integer value : values) {
sum += value;
}
return sum;
}
public static void main(String[] args) {
Java7Calculate java7Calculate = new Java7Calculate();
System.out.println(java7Calculate.sum(1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
}
}
@Profile("java8")
@Service
public class Java8Calculate implements Calculate{
public Integer sum(Integer... values) {
System.out.println("java8");
int sum = Stream.of(values).reduce(0, Integer::sum);
return sum;
}
public static void main(String[] args) {
Java8Calculate java8Calculate = new Java8Calculate();
System.out.println(java8Calculate.sum(1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
}
}
/*
* 启动类
*/
//两种包扫描方式都可以实现
@SpringBootApplication(scanBasePackages = "com.lc.service")
//@ComponentScan(basePackages = "com.lc.service")
public class CalculateBootstrap {
public static void main(String[] args) {
ConfigurableApplicationContext context = new SpringApplicationBuilder(CalculateBootstrap.class)
.web(WebApplicationType.NONE)
.profiles("java8")//指定当前容器使用哪个profile
.run(args);
//判断Bean是否存在
Calculate calculate = context.getBean(Calculate.class);
System.out.println(calculate.sum(1,2,3,4,5,6,7,8,9,10));
//关闭上下文
context.close();
}
}
- 基于编程方式实现 -
@ConditionalOnProperty
/**
* 自定义注解
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
@Documented
@Conditional({OnMyPropertyCondition.class})
public @interface MyConditionalOnProperty {
String value();
String name();
}
/*
* 实现注解,同时编程进行各种判断
*/
public class OnMyPropertyCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Map<String, Object> attributes = metadata.getAnnotationAttributes(MyConditionalOnProperty.class.getName());
String name = (String) attributes.get("name");
String value = (String) attributes.get("value");
String javaValue = System.getProperty(name);//获取系统用户信息,也可以从配置文件中读取
System.out.println(javaValue);
return value.equals(javaValue); //输入值和系统用户名相同,则返回
}
}
/*
* 条件装配,启动类,
*/
public class OnMyPropertyConditionBootstrap {
//创建个Bean,使用条件装配,如果value相同,才会注入IOC容器
@Bean
@MyConditionalOnProperty(name = "user.name",value = "2466")
public String helloWorld(){
return "hello,world";
}
public static void main(String[] args) {
ConfigurableApplicationContext context = new SpringApplicationBuilder(OnMyPropertyConditionBootstrap.class)
.web(WebApplicationType.NONE)//web应用类型,Servlet、Reactive、None,第三章推断web类型详解源码
.run(args);
String bean = context.getBean("helloWorld",String.class);//使用context上下文,获取配置对应的Bean,在value相同时,可以获取,在value不同时,则会报错,容器中没有该Bean
System.out.println(bean);
//关闭上下文
context.close();
}
}
第五节:Spring Boot 自动装配
定义
- 基于规约大于配置,实现spirng组件自动装配的目的
底层装配方式
-
Spirng
模式注解 -
Spirng @Enable
模块 -
Spirng
条件装配 Spirng
工厂加载机制
- 实现类
SpringFactoriesLoader
- 配置资源
META-INF/spring.factories
实现步骤
- 激活自动装配 -
@EnableAutoConfiguration
- 实现自动装配 -
XXXAutoConfiguration
- 配置自动装配实现 -
META/INFO/spring.factories