spring注解驱动开发
参考:https://www.bilibili.com/video/BV1Qz4y197SF?p=23&vd_source=aa4e16557c3a6622877c08d8d7a0a57f
一:AnnotationConfigApplicationContext
import com.hdx.hkafka.config.BeanConfigRation; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class SpringTest { public static void main(String[] args) { // 方式1 ApplicationContext ac1 = new ClassPathXmlApplicationContext("ApplicationContext.xml"); // 方式2 @Configuration ApplicationContext ac2 = new AnnotationConfigApplicationContext(BeanConfigRation.class); // 方式3 @@SpringBootApplication注解的启动类 ApplicationContext ac3 = new AnnotationConfigApplicationContext(HkafkaApplication.class); System.out.println(ac3.getBean("testController")); } }
二:组件添加,组件注册
2.1:@ComponentScan
jdk1.8开始支持可以在一个类似写多个:@ComponentScan
import com.hdx.hkafka.bean.Car;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
@Configuration
@ComponentScan(value = "com.hdx.hkafka", excludeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Component.class, Service.class})})
@ComponentScan(value = "com.hdx.hkafka", includeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Component.class, Service.class})}
//配置includeFilters生效
,useDefaultFilters = false)
// @ComponentScan value:指定要扫描的包
// excludeFilters=Filter[]:指定扫描的时候按照什么规则排除那些组件 type:指定过滤规则根据注解还是其它方式,classes:指定过滤的注解
// includeFilters=Filter[]:指定扫描的时候只需要包含哪些组件 type:指定过滤规则根据注解还是其它方式,classes:指定过滤的注解
public class BeanConfigRation {
@Bean(initMethod="init", destroyMethod="detory")
public Car getCar(){
return new Car();
}
}
jdk1.8之前可以使用:@ComponentScans
import com.hdx.hkafka.bean.Car;
import org.springframework.context.annotation.*;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
@ComponentScans({ @ComponentScan(value = "com.hdx.hkafka", excludeFilters = { @ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Component.class, Service.class})}), @ComponentScan(value = "com.hdx.hkafka", includeFilters = { @ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Component.class, Service.class})} //配置includeFilters生效 ,useDefaultFilters = false) }) // @ComponentScan value:指定要扫描的包 // excludeFilters=Filter[]:指定扫描的时候按照什么规则排除那些组件 type:指定过滤规则根据注解还是其它方式,classes:指定过滤的注解 // includeFilters=Filter[]:指定扫描的时候只需要包含哪些组件 type:指定过滤规则根据注解还是其它方式,classes:指定过滤的注解 public class BeanConfigRation { @Bean(initMethod="init", destroyMethod="detory") public Car getCar(){ return new Car(); } }
ComponentScan可以结合Configuration或者
@Configuration
@ComponentScan
或者
@ComponentScan
@SpringBootApplication
@ComponentScan.Filter
@ComponentScan(value = "com.hdx.hkafka", includeFilters = { @ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Component.class, Service.class}), @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,classes = {ConsumerFastStart.class}), @ComponentScan.Filter(type = FilterType.CUSTOM,classes = {MyTypeFilter.class}) }
FilterType.ANNOTATION 按照注解
FilterType.ASSIGNABLE_TYPE 按照给定的类型
FilterType.CUSTOM 自定义
1、需要自定义一个类实现TypeFilter接口,编写自己想要的规则
import org.springframework.core.io.Resource; import org.springframework.core.type.AnnotationMetadata; import org.springframework.core.type.ClassMetadata; import org.springframework.core.type.classreading.MetadataReader; import org.springframework.core.type.classreading.MetadataReaderFactory; import org.springframework.core.type.filter.TypeFilter; import java.io.IOException; public class MyTypeFilter implements TypeFilter { /** * * @param metadataReader 读取到的当前正在扫描的类的信息 * @param metadataReaderFactory 可以获取到其他任何类信息的 * @return boolean * @throws IOException */ @Override 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(); // 满足条件则匹配 if(className.contains("service")) { return true; } return false; } }
2.2:@Scope
import com.hdx.hkafka.bean.Car; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Scope; /* * 构造(对象创建) 单实例:在容器启动的时候创建对象 多实例:在每次获取的时候创建对象 * */ @Configuration public class BeanConfigRation { /** * ConfigurableBeanFactory.SCOPE_PROTOTYPE, * ConfigurableBeanFactory.SCOPE_SINGLETON, * org.springframework.web.context.WebApplicationContext.SCOPE_REQUEST, * org.springframework.web.context.WebApplicationContext.SCOPE_SESSION * @return * * prototype:多实例的:ioc容器启动并不会去调用方法创建对象放在容器中。每次获取的时候才会调用方法创建对象 * singleton:单实例的(默认值):ioc容器启动会调用方法创建对象放到ioc容器中。以后每次获取就是直接从容器(map.get())中拿, * request:同一次请求创建一个实例 * session:同一个session创建一个实例 */ @Scope("prototype") @Bean("car") public Car getCar(){ return new Car(); }
2.3:@Lazy
package com.hdx.hkafka.config; import com.hdx.hkafka.bean.Car; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Lazy; @Configuration public class TestBeanConfigRation { /** * ConfigurableBeanFactory.SCOPE_PROTOTYPE, * ConfigurableBeanFactory.SCOPE_SINGLETON, * org.springframework.web.context.WebApplicationContext.SCOPE_REQUEST, * org.springframework.web.context.WebApplicationContext.SCOPE_SESSION * @return * * prototype:多实例的 * singleton:单实例的(默认值) * request:同一次请求创建一个实例 * session:同一个session创建一个实例 * * 懒加载: * 单实例bean:默认在容器启动的时候创建对象; * 懒加载:容器启动不创建对象。第一次使用(获取)Bean创建对象,并初始化; */ @Lazy @Bean("car") public Car getCar(){ return new Car(); } }
2.4:@Conditional系类
2.4.1:@Conditional可以作用在方法上,也可以作用在类上。
import com.hdx.hkafka.test.MyCondition; import org.springframework.context.annotation.Conditional; import org.springframework.stereotype.Component; /** * 满足当前条件,这个类中配置的所有bean注册才能生效 */ @Conditional({MyCondition.class}) @Component public class ConditionalTest { }
:2.4.2:@ConditionalOnProperty可以作用在方法上,也可以作用在类上。
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.stereotype.Component; /** * 满足当前条件,这个类中配置的所有bean注册才能生效 */ @ConditionalOnProperty( // 属性key prefix = "spring.bean.is.open", // 属性值 value = "on", // 如果用户不配置默认是否有效 matchIfMissing = true ) @Component public class ConditionalTest { }
2.4.3:@ConditionalOnBean可以作用在方法上,也可以作用在类上。
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.stereotype.Component; /** * DataSource在spring容器中存在则有效 */ @ConditionalOnBean(javax.sql.DataSource.class) @Component public class ConditionalTest { }
2.4.4:@ConditionalOnMissingBean可以作用在方法上,也可以作用在类上。
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.stereotype.Component; /** * 在spring容器中不存在DataSource类型的数据则有效 */ @ConditionalOnMissingBean(javax.sql.DataSource.class) @Component public class ConditionalTest { }
@ConditionalOnBean:该注解的参数对应的类必须存在,否则不解析该注解修饰的配置类;
@ConditionalOnMissingBean:该注解表示,如果存在它修饰的类的bean,则不需要再创建这个bean;可以给该注解传入参数例如
2.4.5:@ConditionalOnClass
@ConditionalOnClass注解判断配置的类是否存在的方式是通过Class.forName的方式
import com.hdx.hkafka.bean.Car; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.stereotype.Component; /** * 在spring容器中存在com.hdx.hkafka.bean.Car类型的数据则有效 */ @ConditionalOnClass(value = {Car.class}) @Component public class ConditionalTest { }
2.4.6:@ConditionalOnMissingClass可以作用在方法上,也可以作用在类上。
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass; import org.springframework.stereotype.Component; /** * 在spring容器中不存在com.hdx.hkafka.bean.Car类型的数据则有效 */ @ConditionalOnMissingClass("com.hdx.hkafka.bean.Car") @Component public class ConditionalTest { }
2.4.7:@ConditionalOnMissingFilterBean可以作用在方法上,也可以作用在类上。
2.5:@Import
给容器中注册组件; 1)、包扫描+组件标注注解(@Controller/@Service/@Repository/@Component)[自己写的类] 2)、@Bean[导入的第三方包里面的组件] 3)、@Import[快速给容器中导入一个组件] 1)、@Import(要导入到容器中的组件);容器中就会自动注册这个组件,id默认是全类名 2)、ImportSelector:返回需要导入的组件的全类名数组; 3)、ImportBeanDefinitionRegistrar:手动注册bean到容器中 4)、使用Spring提供的FactoryBean(工厂Bean) 1)、默认获取到的是工厂bean调用getobject创建的对象 2)、要获取工厂Bean本身,我们需要给id前面加一个& &colorFactoryBean
2.5.1:@Import
package com.hdx.hkafka.config; import com.hdx.hkafka.bean.Car; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; // @Import导入组件,id默认是组件的全类名,value是一个数组Class<?>[] value() @Import(Car.class) @Configuration public class ImportTest { }
2.5.2:ImportSelector
import org.springframework.context.annotation.ImportSelector; import org.springframework.core.type.AnnotationMetadata; //自定义逻辑返回需要导入的组件 public class MyImportSelector implements ImportSelector { //返回值,就是到导入到容器中的组件全类名 //AnnotationMetadata:当前标注@Tmport注解的类的所有注解信息 @Override public String[] selectImports(AnnotationMetadata importingClassMetadata) { // TODO Auto-generated method stub //importingClassMetadata //方法不要返回nu11值 return new String[]{"com.hdx.hkafka.bean.Car"}; } }
import com.hdx.hkafka.test.MyImportSelector; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; // 也可以定义实现ImportSelector接口的类返回一组需要加入容器的bean @Import({MyImportSelector.class}) @Configuration public class ImportTest { }
2.5.3:MyImportBeanDefinitionRegistrar
import com.hdx.hkafka.bean.Car; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; import org.springframework.core.type.AnnotationMetadata; public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar { /** * AnnotationMetadata:当前类的注解信息 * BeanDefinitionRegistry:BeanDefinition注册类; * 把所有需要添加到容器中的bean;调用 * BeanDefinitionRegistry.registerBeanDefinition手工注册进来 */ @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { // 判断当前容器中是否存在此类型的bena boolean definition = registry.containsBeanDefinition("com.hdx.hkafka.chapter1.ProducerDemo"); boolean definition2 = registry.containsBeanDefinition("com.hdx.hkafka.chapter1.ConsumerFastStart"); if(definition && definition2){ //(Bean的类型,Bean。//指定Bean定义信息;。) RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(Car.class); //注册一个Bean,指定bean名 registry.registerBeanDefinition("car", rootBeanDefinition); } } }
import com.hdx.hkafka.test.MyImportBeanDefinitionRegistrar; import com.hdx.hkafka.test.MyImportSelector; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; // 也可以定义实现ImportSelector接口的类返回一组需要加入容器的bean @Import({MyImportSelector.class,MyImportBeanDefinitionRegistrar.class}) @Configuration public class ImportTest { }
2.5.4:FactoryBean
import com.hdx.hkafka.bean.Car; import org.springframework.beans.factory.FactoryBean; //创建一个Spring定义的FactoryBean public class MyFactoryBean implements FactoryBean { //返回一个Car对象,这个对象会添加到容器中 @Override public Car getObject() throws Exception { return new Car(); } @Override public Class<?> getObjectType() { return Car.class; } //是单例? // true:这个bean是单实例,在容器中保存一份 // false:多实例,每次获取都会创建一个新的bean; @Override public boolean isSingleton() { return false; } }
import com.hdx.hkafka.test.MyFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ImportTest {
/**
* 4)、使用Spring提供的FactoryBean(工厂Bean)
* 1)、默认获取到的是工厂bean调用getobject创建的对象
* 2)、要获取工厂Bean本身,我们需要给id前面加一个&
* &colorFactoryBean
*/
@Bean
public MyFactoryBean myFactoryBean(){
return new MyFactoryBean();
}
}
三:bean生命周期
构造(对象创建)单实例:
在容器启动的时候创建对象多实例:
在每次获取的时候创建对象
BeanPostProcessor.postProcessBeforeInitialization
初始化:
对象创建完成,并赋值好,调用初始化方法。。。BeanPostProcessor.postProcessAfterInitialization
销毁:
单实例:容器关闭的时候多实例:
容器不会管理这个bean;容器不会调用销毁方法;
初始化bean操作:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean
遍历得到容器中所有的BeanPostProcessor;挨个执行befforeInitialization
一但返回null,跳出for循环,不会执行后面的BeanPostProcessor.postProcessBeforeInitialization
BeanPostProcessor原理
populateBean(beanName, mbd, instanceWrapper);|给bean属性赋值
initializeBean{
applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
invokeInitMethods(beanName, wrappedBean, mbd);
applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
1)、指定初始化和销毁方法;通过@Bean指定init-method和destroy-method;
2)、通过让Bean实现InitializingBean(定义初始化逻辑),DisposableBean(定义销毁逻辑);
3)、可以使用JSR250;@PostConstruct:在bean创建完成并且属性赋值完成;来执行初始化方法@PreDestroy:在容器销毁bean之前通知我们进行清理工作
4)、BeanPostProcessor【interface】:bean的后置处理器;在bean初始化前后进行一些处理工作;
postProcessBeforeInitialization:在初始化之前工作
postProcessAfterInitialization:在初始化之后工作
Spring底层对BeanPostProcessor的使用;
bean赋值,注入其他组件,@Autowired,生命周期注解功能,@Async,xxx BeanPostProcessor;
3.1:执行初始化和销毁的方式
3.1-1:使用bean注解执行类初始化和销毁执行的方法
前提:必读加入spring容器且是单例情况下
构造(对象创建)
单实例:在容器启动的时候创建对象
多实例:在每次获取的时候创建对象,spring不会管理bean,所以此时指定销毁和初始化方法无效
@Configuration public class BeanConfigRation { @Bean(initMethod="init", destroyMethod="detory") public Car getCar(){ return new Car(); } }
public class Car { public Car() { System.out.println("Car"); } public void init() { System.out.println("init"); } public void detory() { System.out.println("detory"); } }
3.1-2:实现InitializingBean, DisposableBean
import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.stereotype.Component; @Component public class People implements InitializingBean, DisposableBean { /*类的属性赋值完成后*/ @Override public void afterPropertiesSet() throws Exception { System.out.println("afterPropertiesSet"); } /*在bean被销毁时*/ @Override public void destroy() throws Exception { System.out.println("destroy"); } }
3.1-3:使用@PostConstruct和@PreDestroy
实现类:org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor
还有:
postProcessBeforeInitialization调用初始化方法
postProcessBeforeDestruction调用销毁方法
/** * Specify the init annotation to check for, indicating initialization * methods to call after configuration of a bean. * <p>Any custom annotation can be used, since there are no required * annotation attributes. There is no default, although a typical choice * is the JSR-250 {@link javax.annotation.PostConstruct} annotation. */ public void setInitAnnotationType(Class<? extends Annotation> initAnnotationType) { this.initAnnotationType = initAnnotationType; } /** * Specify the destroy annotation to check for, indicating destruction * methods to call when the context is shutting down. * <p>Any custom annotation can be used, since there are no required * annotation attributes. There is no default, although a typical choice * is the JSR-250 {@link javax.annotation.PreDestroy} annotation. */ public void setDestroyAnnotationType(Class<? extends Annotation> destroyAnnotationType) { this.destroyAnnotationType = destroyAnnotationType; }
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());
try {
metadata.invokeInitMethods(bean, beanName);
}
catch (InvocationTargetException ex) {
throw new BeanCreationException(beanName, "Invocation of init method failed", ex.getTargetException());
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Failed to invoke init method", ex);
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
@Override
public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException {
LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());
try {
metadata.invokeDestroyMethods(bean, beanName);
}
catch (InvocationTargetException ex) {
String msg = "Destroy method on bean with name '" + beanName + "' threw an exception";
if (logger.isDebugEnabled()) {
logger.warn(msg, ex.getTargetException());
}
else {
logger.warn(msg + ": " + ex.getTargetException());
}
}
catch (Throwable ex) {
logger.warn("Failed to invoke destroy method on bean with name '" + beanName + "'", ex);
}
}
import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; @Component public class People { /*类的属性赋值完成后*/ @PostConstruct public void init() throws Exception { System.out.println("init"); } /*在bean被销毁时*/ @PreDestroy public void destroy() throws Exception { System.out.println("destroy"); } }
3.1-4:BeanPostProcessor原理
初始化bean操作:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean
遍历得到容器中所有的BeanPostProcessor;挨个执行befforeInitialization
一但返回null,跳出for循环,不会执行后面的BeanPostProcessor.postProcessBeforeInitialization
BeanPostProcessor原理
populateBean(beanName, mbd, instanceWrapper);|给bean属性赋值
initializeBean{
applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
invokeInitMethods(beanName, wrappedBean, mbd);
applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;
/**
* 后置处理器:初始化前后进行处理工作
*/
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
/**
* 初始化前调用
* @param bean
* @param beanName
* @return
* @throws BeansException
*/
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
/**
* 初始化后调用
* @param bean
* @param beanName
* @return
* @throws BeansException
*/
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
3.1-5:ApplicationContextAware应用
import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.core.env.Environment; import org.springframework.stereotype.Component; /** * 原理类:org.springframework.context.support.ApplicationContextAwareProcessor */ @Component public class SpringUtils implements ApplicationContextAware { private static ApplicationContext applicationContext; // 原理类:org.springframework.context.support.ApplicationContextAwareProcessor @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } public static ApplicationContext getApplicationContext() { return applicationContext; } /** * 当前spring中配置的参数对象 * @return */ public static Environment getEnvironment() { return applicationContext.getEnvironment(); } }
四:属性赋值
4.1:@Value
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
@Component
public class People {
// 直接赋值
@Value("张三")
private String name;
// 使用spel
@Value("#{32-14}")
private String age;
// 读取properties配置文件赋值
@Value("${test.desc}")
private String desc;
}
4.2:@PropertySource(value={})
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
// 使用@PropertySource读取外部配置文件中的k/v保存到运行的环境变量中;加款完外部的配置文件以后使用${}取出配置文件的值
@PropertySource(value={"classpath:/application.properties"})
@Configuration
public class TestBeanConfigRation {
}
// 获取对应属性配置值
ConfigurableEnvironment environment = ApplicationContext.getEnvironment();
String property = environment.getProperty("person.nickName");
ApplicationContext.close();
五:自动装配
5.1:@Autowired
@Autowired:构造器,参数,方法,属性:
// @Qualifier("bookDao"):使用@Qualifier指定需要装配的组件的id,而不是使用属性名 @Qualifier("people") // 1、先使用People.class类型在容器中查找 // 2、再使用people1作为bean名称在容器中查找 // 3、required = false设置如果没有不抛异常 @Autowired(required = false) private People people1;
import org.springframework.context.annotation.Primary; import org.springframework.stereotype.Component; // Primary作用在类和方法上标准当前类的实例在容器中级别中默认等级最高 @Primary @Component public class People { }
在set方法上
import com.hdx.hkafka.bean.People; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RestController; @RestController public class OrderController { // 标注在方法,Spring容器创建当前对象,就会调用方法,完成赋值; // 方法使用的参数,自定义类型的值从ioc容器中获取 @Autowired public void setPeople2(People people2) { this.people2 = people2; } private People people2; }
在构造方法
import com.hdx.hkafka.bean.People; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RestController; //默认加在ioc容器中的组件,容器启动会调用无参构造器创建对象,再进行初始化赋值等操作 @RestController public class OrderController { // 构造器要用的组件,都是从容器中获取 @Autowired public OrderController(People people) { this.people = people; } private People people; }
在有参数构造器
import com.hdx.hkafka.bean.People; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RestController; @RestController public class OrderController { public OrderController(@Autowired People people) { this.people = people; } private People people; }

@Bean+方法参数:参数从容器中获取;默认不写@Autowired效果是一样的:都能自动装配
// @Bean标注的方法创建对象的时候,方法参数的值从容器中获取 @Bean public People getCar(People people){ System.out.println(people); return new People(); }
5.2:Spring还支持使用@Resource(JSR250)和@Inject(JSR330)[java规范的注解]
@Resource
import com.hdx.hkafka.bean.People; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; @RestController public class OrderController { // 可以和@Autowired一样实现自动装配功能:默认是按照组件名称进行装配的 // 没有能支持@Primary功能没有支持@Autowired(reqiured=false) @Resource(name = "people2") private People people2; }
@Inject
需要导入javax.inject的包,和Autowired的功能一样。没有required=false的功能
<!-- https://mvnrepository.com/artifact/javax.inject/javax.inject --> <dependency> <groupId>javax.inject</groupId> <artifactId>javax.inject</artifactId> <version>1</version> </dependency>
import com.hdx.hkafka.bean.People; import org.springframework.web.bind.annotation.RestController; import javax.inject.Inject; @RestController public class OrderController { @Inject private People people2; }
5.3:Aware接口
完成路径:org.springframework.beans.factory.Aware
自定义组件想要使用Spring容器底层的一些组件(ApplicationContext,BeanFactory,xxx);
自定义组件实现xxxAware;在创建对象的时候,会调用接口规定的方法注入相关组件;Aware;
把Spring底层一些组件注入到自定义的Bean中;
xxxAware:功能使用xxxProcessor;
ApplicationContextAware==>ApplicationContextAwareProcessor;
示例
import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanNameAware; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.context.EmbeddedValueResolverAware; import org.springframework.core.env.Environment; import org.springframework.stereotype.Component; import org.springframework.util.StringValueResolver; /** * 原理类:org.springframework.context.support.ApplicationContextAwareProcessor */ @Component public class SpringUtils implements ApplicationContextAware, EmbeddedValueResolverAware, BeanNameAware { private static ApplicationContext applicationContext; // 原理类:org.springframework.context.support.ApplicationContextAwareProcessor @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } public static ApplicationContext getApplicationContext() { return applicationContext; } /** * 当前spring中配置的参数对象 * @return */ public static Environment getEnvironment() { return applicationContext.getEnvironment(); }
// EmbeddedValueResolverAware // 设置用于解析嵌入定义值的StringValueResolver。 @Override public void setEmbeddedValueResolver(StringValueResolver resolver) { String val = resolver.resolveStringValue("你好${os.name}我是#{20*18}"); System.out.println("解析的字符串:"+ val); } // BeanNameAware @Override public void setBeanName(String name) { System.out.println("当前bean的名字:"+ name); } }
5.3:Profile注解
Profile:
Spring为我们提供的可以根据当前环境,动态的激活和切换一系列bean的功能
import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented @Conditional({ProfileCondition.class}) public @interface Profile { String[] value(); }
验证类:
import com.mchange.v2.c3p0.ComboPooledDataSource; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.EmbeddedValueResolverAware; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Profile; import org.springframework.context.annotation.PropertySource; import org.springframework.util.StringValueResolver; import javax.sql.DataSource; /** * * 开发环境、测试环境、生产环境; * 数据源:(/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; @Profile("dev") @Bean("dataSourcelDev") public DataSource dataSourcelDev(@Value("${db.password}")String pwd) throws Exception{ ComboPooledDataSource dataSource = new ComboPooledDataSource(); dataSource.setUser(user); dataSource.setPassword(pwd); dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test"); String dirverClass = valueResolver.resolveStringValue("${db.driverClass}"); dataSource.setDriverClass("com.mysql.jdbc.Driver"); return dataSource; } @Profile("sit") @Bean("dataSourcelSit") public DataSource dataSourcelSit(@Value("${db.password}")String pwd) throws Exception{ ComboPooledDataSource dataSource = new ComboPooledDataSource(); dataSource.setUser(user); dataSource.setPassword(pwd); dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test"); String dirverClass = valueResolver.resolveStringValue("${db.driverClass}"); dataSource.setDriverClass(dirverClass); return dataSource; } // 默认生效 @Profile("default") @Bean("dataSourcelDefault") public DataSource dataSourcelDefault(@Value("${db.password}")String pwd) throws Exception{ ComboPooledDataSource dataSource = new ComboPooledDataSource(); dataSource.setUser(user); dataSource.setPassword(pwd); dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test"); String dirverClass = valueResolver.resolveStringValue("${db.driverClass}"); dataSource.setDriverClass(dirverClass); return dataSource; } @Override public void setEmbeddedValueResolver(StringValueResolver resolver) { this.valueResolver = resolver; } }
配置文件:
db.user=root db.password=root db.driverClass=com.mysql.jdbc.Driver
测试类:
import com.hdx.hkafka.test.MainConfigOfProfile;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import javax.sql.DataSource;
public class MainConfigOfProfileTest {
private void test() {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfProfile.class);
String[] names = applicationContext.getBeanNamesForType(DataSource.class);
for (int i = 0; i < names.length; i++) {
System.out.println(names[i]);
}
applicationContext.close();
}
// 1、使用命令行动态参数:在虚拟机参数位置加载-Dspring.profiles.active=test
@Test
public void test1() {
// 验证执行
test();
}
/**
* 2、代码的方式激活某种环境;
* 2.1、创建一个applicationContext
* 2.2、设置需要激活的环境applicationContext.getEnvironment().setActiveProfiles("test","dev");
* 2.3、注册主配置类applicationContext.register(MainConfigOfProfile.class);
* 2.4、启动刷新容器applicationContext.refresh();
*/
@Test
public void test2() {
AnnotationConfigApplicationContext applicationContext =new AnnotationConfigApplicationContext();
applicationContext.getEnvironment().setActiveProfiles("test","dev");
applicationContext.register(MainConfigOfProfile.class);
applicationContext.refresh();
// 验证执行
test();
}
}


浙公网安备 33010602011771号