第二章:走向自动装配
第一节: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