1.系列总览
SpringBoot的核心特性:
2.自动装配
2.1.SpringFrameWork的手动装配
2.1.1Spring 模式注解装配
自定义模式注解
@Component “派生性” 需要注意的是签名要保持一致
@Target(ElementType.TYPE)
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Component
public @interface FirstLevelRepository {
//签名保持一致
String value() default "";
}
使用这个注解:
package com.wx.springbootdemo.repository;
import com.wx.springbootdemo.annotation.FirstLevelRepository;
/**
* User: Mr.Wang
* Date: 2019/10/21
*/
@FirstLevelRepository(value = "myRepository")
public class MyRepository {
}
测试@Component的派生注解是否成功
package com.wx.springbootdemo.bootstrap;
import com.wx.springbootdemo.repository.MyRepository;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;
/**
* User: Mr.Wang
* Date: 2019/10/21
*/
@ComponentScan(basePackages = "com.wx.springbootdemo.repository")
public class MainApplication {
public static void main(String[] args) {
ConfigurableApplicationContext applicationContext = new SpringApplicationBuilder(MainApplication.class)
.web(WebApplicationType.NONE)
.run(args);
MyRepository myRepository = applicationContext.getBean("myRepository", MyRepository.class);
System.out.println(myRepository);
//关闭上下文对象
applicationContext.close();
}
}
ok,可以获得这个bean
@Component “层次性”
理解上面的派生性和层次性后,@SpringBootApplication注解也是从@Compoment派生和层次来的
2.1.2 Spring @Enable 模块装配
Spring Framework 3.1 开始支持”@Enable 模块驱动“。所谓“模块”是指具备相同领域的功能组件集合, 组合所形成一个独立
的单元。比如 Web MVC 模块、AspectJ代理模块、Caching(缓存)模块、JMX(Java 管 理扩展)模块、Async(异步处
理)模块等。
自定义Enable模块,分为注解驱动和接口资实现两种方式来实现自定义Enable模块
基于注解实现的方式具体可以参考@EnableWebMv模块的实现,基于接口实现的方式具体可以参考@EnableCaching模块的实现。
现在我们子当以一个HelloWorld模块,先基于注解驱动的方式来实现他。先参考一下@EnableWebMv模块的实现
参考上面,实现下面
ok,现在我可以测试一下这个模块开启后是否可用
package com.wx.springbootdemo.bootstrap;
import com.wx.springbootdemo.annotation.EnableHelloWorld;
import com.wx.springbootdemo.repository.MyRepository;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.ConfigurableApplicationContext;
/**
* User: Mr.Wang
* Date: 2019/10/21
*/
@EnableHelloWorld
public class MainEnable {
public static void main(String[] args) {
ConfigurableApplicationContext applicationContext = new SpringApplicationBuilder(MainEnable.class)
.web(WebApplicationType.NONE)
.run(args);
String helloWord = applicationContext.getBean("helloWord", String.class);
System.out.println(helloWord);
//
applicationContext.close();
}
}
接下来实现接口驱动的方式:
参考@EnableCaching
参考上面实现下面:
测试没有问题。实现接口的这种方式呢有弹性,可以自定义实现多个返回值
2.1.3 Spring 条件装配
基于配置的方式@Profile实现多个整数相加的功能
package com.wx.springbootdemo.servcie;
/**
* User: Mr.Wang
* Date: 2019/10/21
*/
public interface CalculationService {
public Integer sum(Integer ... values);
}
package com.wx.springbootdemo.servcie.imp;
import com.wx.springbootdemo.servcie.CalculationService;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Service;
/**
* User: Mr.Wang
* Date: 2019/10/21
*/
@Profile("java7")
@Service
public class Java7CalculationServiceImp implements CalculationService {
@Override
public Integer sum(Integer... values) {
System.out.println("java7 for 循环实现");
int sum = 0;
for (Integer value : values) {
sum += value;
}
return sum;
}
}
package com.wx.springbootdemo.servcie.imp;
import com.wx.springbootdemo.servcie.CalculationService;
import org.apache.el.stream.Stream;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Service;
import java.util.Arrays;
/**
* User: Mr.Wang
* Date: 2019/10/21
*/
@Profile("java8")
@Service
public class Java8CalculationServiceImp implements CalculationService {
@Override
public Integer sum(Integer... values) {
System.out.println("java8 lambda 循环实现");
Integer reduce = Arrays.stream(values).reduce(0, Integer::sum);
return reduce;
}
}
测试:
package com.wx.springbootdemo.bootstrap;
import com.wx.springbootdemo.servcie.CalculationService;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import java.util.Arrays;
/**
* User: Mr.Wang
* Date: 2019/10/21
*/
@ComponentScan(basePackages = "com.wx.springbootdemo.servcie.*")
public class MainConditionalAssembly {
public static void main(String[] args) {
ConfigurableApplicationContext applicationContext = new SpringApplicationBuilder(MainConditionalAssembly.class)
.web(WebApplicationType.NONE)
.profiles("java8")
.run(args);
CalculationService bean = applicationContext.getBean(CalculationService.class);
Integer sum = bean.sum(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
System.out.println(sum);
//
applicationContext.close();
}
}
接下来使用编程条件装配@Conditional来实现相同的功能,我们参考@ConditionalOnClass来实现一个@ConditionalOnSystemProperty,他的功能是判断属性是否满足系统的属性。
参看上面实现下面:我们这个注解的作用是判断条件是否和系统的值相等
package com.wx.springbootdemo.condition;
import org.springframework.context.annotation.Conditional;
import java.lang.annotation.*;
/**
* User: Mr.Wang
* Date: 2019/10/21
*/
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional({OnSystemPropertyCondition.class})
public @interface ConditionalOnSystemProperty {
String value() default "";
String name() default "";
}
package com.wx.springbootdemo.condition;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
import java.util.Map;
/**
* User: Mr.Wang
* Date: 2019/10/21
*/
public class OnSystemPropertyCondition implements Condition {
@Override
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
Map<String, Object> attributes =
annotatedTypeMetadata.getAnnotationAttributes(ConditionalOnSystemProperty.class.getName());
String name = String.valueOf(attributes.get("name"));
String value = String.valueOf(attributes.get("value"));
String name1 = System.getProperty(name);
return name1.equals(value);
}
}
使用,当条件满足,那么Bean会加载,打印输出,如果条件不满足就找不到这个Bean
package com.wx.springbootdemo.bootstrap;
import com.wx.springbootdemo.condition.ConditionalOnSystemProperty;
import com.wx.springbootdemo.repository.MyRepository;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
/**
* User: Mr.Wang
* Date: 2019/10/21
*/
public class MainConditional {
@Bean
@ConditionalOnSystemProperty(name = "user.name", value = "wangxiang")
public String helloWorld() {
return "I'm iron man";
}
public static void main(String[] args) {
ConfigurableApplicationContext applicationContext = new SpringApplicationBuilder(MainConditional.class)
.web(WebApplicationType.NONE)
.run(args);
String bean = applicationContext.getBean(String.class);
System.out.println(bean);
applicationContext.close();
}
}
2.2.SpringBoot的自动装配
实现自定义的自动装配,实现HelloWorld的自动配置,之前不是有什么模式装配,@Enable模块装配,条件装配吗。
现在用这些来实现HelloWorld模块的自动装配。
实现需要三步走
第一步激活自动装配,只有激活这个自动装配了,Spring的工厂才会去读取配置的spring.factories 文件来自动装配,
第一步激活自动装配以后就会Spring的工厂SpringFactoriesLoader 就会加载这个文件,第二步就是实现自动装配
然后他会通过反射去创建这些配置类
配置累的编写参考:WebMvcAutoConfiguration
参考上面:
第三步就是配置自动装配实现
测试:
ok没有问题