如何你没有了解过Spring Boot和Spring Cloud 那么 这篇文章就是你了解Spring Boot和Spring Cloud 的垫脚石。
1.给容器中注册组件
加入spring-context 包
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.12.RELEASE</version>
</dependency>
新建一个Class 为配置类 并且在类(称为配置类,一个为Xml 方式 ,一个为配置类的方式)上加入Configuration 告诉Spring 这个一个配置类
@Configuration
public class MainConfig {
//给容器注册一个bean;类型为返回值得类型,Id默认为方法名称作为ID,
@Bean
public Person person(){
return new Person("zhangsan",20);
}
}
那么如何测试呢?
我们可以利用AnnotationConfigApplicationContext
public static void main(String [] args){
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
Person person = applicationContext.getBean(Person.class);
System.out.println(person);
}
使用CompoentScan自动扫描组件
@ComponentScan(value = {"com.zhh"})
@Configuration
public class MainConfig {
//给容器注册一个bean;类型为返回值得类型,Id默认为方法名称作为ID,
@Bean
public Person person01(){
return new Person("zhangsan",20);
}
}
测试代码:
public class IOCTest {
@SuppressWarnings("resource")
@Test
public void testIOCTest(){
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
String [] beanNames = applicationContext.getBeanDefinitionNames();
for(String str:beanNames){
System.out.println(str);
}
//结果为:bookDao person01 mainConfig
}
}
这里可以使用excludeFilters 排除一些bean 也可以使用IncludeFilters 包含一些bean
@ComponentScan(value = {"com.zhh"},excludeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Controller.class, Service.class})
//这里排除 Controller 和 Service
})
@ComponentScan(value = {"com.zhh"},includeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Controller.class})
//这里只包含 Controller 同时需要禁用默认的过略规则
},useDefaultFilters = false)
@Configuration
public class MainConfig {
//给容器注册一个bean;类型为返回值得类型,Id默认为方法名称作为ID,
@Bean
public Person person01(){
return new Person("zhangsan",20);
}
}
同时也可以自定义TypeFilter指定过滤规则
@ComponentScan.Filter(type = FilterType.CUSTOM,classes = MyTypeFilter.class)
//FilterType.CUSTOM 自定义过滤规则 过滤规则有子类MyFilter 实现TypeFilter接口
public class MyTypeFilter implements TypeFilter {
/**
*
* @param metadataReader 读取到当前正在扫描类的信息
* @param metadataReaderFactory 可以获取到其他任何类的信息
* @return
* @throws IOException
*/
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
//获取当前类注解的信息
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
ClassMetadata classMetadata = metadataReader.getClassMetadata();
Resource resource = metadataReader.getResource();
String className = classMetadata.getClassName();
System.out.println("-->当前配置类的信息"+className);
if(className.contains("er")){//如果ClassName 包含er 咋返回true
return true;
}
return false;
}
}
使用Scope设置组件作用域 @Scope
@Configuration
public class MainConfig2 {
//默认为单实例 无论多少次获取都是同一个对象
/**
* prototype :多实例的 ioc容器启动 并不会去调用方法创建对象放在容器中,每次获取的时候才会创建
* singleton : 单实例(默认的) ioc容器启动后,会创建对象放到IOC容器中,以后每次获取就是直接从容器(map.get)一个对象
* request:同一个请求创建一个实例
* session:同一个session创建一个事例
* @return
*/
@Scope
@Bean
public Person person(){
return new Person("lisi",23);
}
}
Lazy-bean 设置懒加载
懒加载:针对单实例bean:默认在容器启动的时候创建对象
容器启动不创建对象,第一次使用(获取)Bean创建对象,并初始化
@Lazy
@Bean
public Person person(){
return new Person("lisi",23);
}
按照条件注册Bean @Conditional:能按照一定的条件进行判断,满足条件给容器中注册Bean.
@Conditional({LinuxCondition.class})
@Bean
public Person person(){
return new Person("lisi",23);
}
@Conditional({WindowsCondition.class})
@Bean
public Person Person02(){
return new Person("zhangsan",23);
}
LinuxCondition.java
public class WindowsCondition implements Condition {
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
Environment environment = conditionContext.getEnvironment();
String property = environment.getProperty("os.name");
if(property.contains("Windows")){ //如果当前运行环境为Windows10 则返回true
return true;
}
return false;
}
}
WindowsCondition.java
public class LinuxCondition implements Condition {
/**
*
* @param conditionContext 判断条件能使用的上下文环境
* @param annotatedTypeMetadata
* @return
*/
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
//TODO 是否是Linux 系统
//获取IOC容器的BeanFacotry
ConfigurableListableBeanFactory beanFactory = conditionContext.getBeanFactory();
//获取类加载器
ClassLoader classLoader = conditionContext.getClassLoader();
//获取当前运行环境
Environment environment = conditionContext.getEnvironment();
//获取bean 定义的注册类
BeanDefinitionRegistry beanDefinitionRegistry = conditionContext.getRegistry();
String properties = environment.getProperty("os.name");
if(properties.contains("Linux")){
return true;
}
return false;
}
}
@Condition 可以放在类上 如果放在类上,则表示 满足当前条件 则装配该类
使用import 给容器快速导入一个组件
1.包扫描+组件标注注解(@Controller/@Service/@Repository/@Component)
2.@Bean[导入的第三方里面的组件]
3.@Import 快速给容器导入一个组件:容器中就会注册一个组件,ID默认是全类名
@Configuration
@Import(Color.class)
//Import 导入组件 Id默认组件的全类名
public class MainConfig2 {
}
interface importSelector:返回需要导入的组件的全类名数组;
@Configuration
@Import({Color.class,MyImportSelector.class})
//Import 导入组件 Id默认组件的全类名
public class MainConfig2 {
}
MyImportSelector.java
public class MyImportSelector implements ImportSelector {
public String[] selectImports(AnnotationMetadata annotationMetadata) {
//返回值,就是导入到容器中的组件的全类名
return new String[]{"com.zhh.Person","com.zhh.Color"};
}
}
使用ImportBeanDefinitionRegistrar 手动注册bean到容器中
@Configuration
@Import({Color.class,MyImportSelector.class,MyImportBeanDefinitionRegistrar.class})
//Import 导入组件 Id默认组件的全类名
public class MainConfig2 {
}
MyImportBeanDefinitionRegistrar.java
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
/**
*
* @param annotationMetadata 当前类注册信息
* @param beanDefinitionRegistry BeanDefinition注册类
*/
public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {
boolean definition = beanDefinitionRegistry.containsBeanDefinition("red");
boolean definition2 = beanDefinitionRegistry.containsBeanDefinition("blue");
if(definition && definition2){ //如果当前IOC容器有Red 类和 Blue类 就注册rabow类
//指定bean 名称
RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(Rabow.class);
beanDefinitionRegistry.registerBeanDefinition("rabow",rootBeanDefinition);
}
}
}
使用Spring提供的FactoryBean(工厂bean)
1.默认获取到的是工厂bean调用getObject 创建对象
2.要获取工厂Bean本身,我们需要给Id前面加一个& 标识
//创建一个Spring定义的FactoryBean
public class ColorFactoryBean implements FactoryBean<Color> {
//返回一个Color对象,在容器中保存一份
public Color getObject() throws Exception {
return new Color();
}
public Class<?> getObjectType() {
return Color.class;
}
//来控制它是否是单例 true 为单例,false 为多实例
public boolean isSingleton() {
return true;
}
}
@Bean
public ColorFactoryBean colorFactoryBean{
return new ColorFactoryBean();
}
IOCTest.java
@Test
public void testIOCTest(){
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);
Object object = applicationContext.getBean("colorFactoryBean");
System.out.println("->>>"+object);
//输出结果 ->>>com.zhh.bean.Color@4f638935
//虽然你装配的是ColorFactoryBean 但是你获取的是Color
}
Bean指定初始化和销毁方法
初始化:对象创建完成,并赋值好,调用初始化方法
销毁:单实例:容器关闭的时候 ,多实例:容器不会管理这个bean,容器不会调用销毁方法
1.指定初始化和销毁方法
@Bean(initMethod = "init",destroyMethod = "destory")
public Car car(){
return new Car();
}
使用InitializingBean 和DisposableBean 接口指定初始化和销毁
public class Cat implements InitializingBean,DisposableBean {
public void destroy() throws Exception {
//容器关闭之后就会调用
}
public void afterPropertiesSet() throws Exception {
//bean创建完成会调用
}
}
使用PostConstruct 和 PreDestroy 注解 调用初始化和销毁方法
public class Dog {
public Dog(){}
@PostConstruct
public void init(){
System.out.println("调用初始化方法");
}
@PreDestroy
public void destory(){
System.out.println("调用销毁方法");
}
}
BeanPostProcess【interface】:bean 的后置处理器
在bean 初始化前后,进行处理工作
1.postProcessBeforeInitialization:在初始化前工作
2.postProcessAfterInitialization:在初始化后工作
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { System.out.println("postProcessBeforeInitialization..."+beanName+"=>"+bean);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessAfterInitialization..."+beanName+"=>"+bean);
return bean;
}
}
属性赋值-@Value
@Date
public class Person {
//使用value赋值
//1.基本数值
//2可以写SpEL;#{}
//3可以写${}取出配置文件中的值(在运行环境中的值)
@Value("张三")
private String name;
@Value("#{20-2}")
private Integer age;
@Value("${person.nickName}")
private String nickName;
}
//使用@PropertySource 读取外部配置文件中的key/value保存到运行环境变量中
@PropertySource(value={"classpath:/person.properties"})
@Configuration
public class MainConfigOfPropertyValues {
@Bean
public Person person(){
return new Person();
}
}
自动装配
/**
* 自动装配;
* Spring利用依赖注入(DI),完成对IOC容器中中各个组件的依赖关系赋值;
*
* 1)、@Autowired:自动注入:
* 1)、默认优先按照类型去容器中找对应的组件:applicationContext.getBean(BookDao.class);找到就赋值
* 2)、如果找到多个相同类型的组件,再将属性的名称作为组件的id去容器中查找
* applicationContext.getBean("bookDao")
* 3)、@Qualifier("bookDao"):使用@Qualifier指定需要装配的组件的id,而不是使用属性名
* 4)、自动装配默认一定要将属性赋值好,没有就会报错;
* 可以使用@Autowired(required=false);
* 5)、@Primary:让Spring进行自动装配的时候,默认使用首选的bean;
* 也可以继续使用@Qualifier指定需要装配的bean的名字,使用@Primary那么@Qualifier 就不能使用了
* BookService{
* @Autowired
* BookDao bookDao;
* }
*
*
*/
@Configuration
@ComponentScan({"com.atguigu.service","com.atguigu.dao",
"com.atguigu.controller","com.atguigu.bean"})
public class MainConifgOfAutowired {
@Primary
@Bean("bookDao2")
public BookDao bookDao(){
BookDao bookDao = new BookDao();
bookDao.setLable("2");
return bookDao;
}
/**
* @Bean标注的方法创建对象的时候,方法参数的值从容器中获取
* @param car
* @return
*/
@Bean
public Color color(Car car){
Color color = new Color();
color.setCar(car);
return color;
}
}
Spring 还支持@Resource(JSR250) 和@Inject (JSR330) [java规范的注解]
@Resouce: 可以和@Autowired 一样完成自动装配的功能;默认是按照组件名称进行装配的;没有能支持@Primary功能,没有@Autowired(Reqiured=false)
@Inject: 需要导入javax.inject的包,和Autowired的功能一样。没有required=false的功能;
@Autowired:Spring定义的; @Resource、@Inject都是java规范
@Autired同时可以标注在构造器上,参数和方法,以及属性上;都是从容器中获取参数组件的值
1.标注在方法上:@Bean +方法参数;参数从容器中获取
2.标在构造器上:如果组件只有一个有参构造器,这个有参构造器的@Autowired可以省略,参数位置的组件还是可以自动从容器中获取
Profile多环境搭建
/**
* Profile:
* Spring为我们提供的可以根据当前环境,动态的激活和切换一系列组件的功能;
*
* 开发环境、测试环境、生产环境;
* 数据源:(/A)(/B)(/C);
*
*
* @Profile:指定组件在哪个环境的情况下才能被注册到容器中,不指定,任何环境下都能注册这个组件
*
* 1)、加了环境标识的bean,只有这个环境被激活的时候才能注册到容器中。默认是default环境
* 2)、写在配置类上,只有是指定的环境的时候,整个配置类里面的所有配置才能开始生效
* 3)、没有标注环境标识的bean在,任何环境下都是加载的;
*/
@PropertySource("classpath:/dbconfig.properties")
@Configuration
public class MainConfigOfProfile implements EmbeddedValueResolverAware{
@Value("${db.user}")
private String user;
private StringValueResolver valueResolver;
private String driverClass;
@Bean
public Yellow yellow(){
return new Yellow();
}
@Profile("test")
@Bean("testDataSource")
public DataSource dataSourceTest(@Value("${db.password}")String pwd) throws Exception{
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setUser(user);
dataSource.setPassword(pwd);
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test");
dataSource.setDriverClass(driverClass);
return dataSource;
}
@Profile("dev")
@Bean("devDataSource")
public DataSource dataSourceDev(@Value("${db.password}")String pwd) throws Exception{
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setUser(user);
dataSource.setPassword(pwd);
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/ssm_crud");
dataSource.setDriverClass(driverClass);
return dataSource;
}
@Profile("prod")
@Bean("prodDataSource")
public DataSource dataSourceProd(@Value("${db.password}")String pwd) throws Exception{
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setUser(user);
dataSource.setPassword(pwd);
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/scw_0515");
dataSource.setDriverClass(driverClass);
return dataSource;
}
@Override
public void setEmbeddedValueResolver(StringValueResolver resolver) {
// TODO Auto-generated method stub
this.valueResolver = resolver;
driverClass = valueResolver.resolveStringValue("${db.driverClass}");
}
}
1.活环境可以在JVM参数位置加载-Dspring.profiles.active=test
2.代码的方式激活环境
public class IOCTest_Profile {
@Test
public void test01(){
AnnotationConfigApplicationContext applicationContext =
new AnnotationConfigApplicationContext();
//1、创建一个applicationContext
//2、设置需要激活的环境
applicationContext.getEnvironment().setActiveProfiles("dev");
//3、注册主配置类
applicationContext.register(MainConfigOfProfile.class);
//4、启动刷新容器
applicationContext.refresh();
}
}
网友评论