Write in front
Due to the update of articles on other topics, the Spring series of articles have not been updated for a long time. Many small partners have left messages in the background of the official account or directly privately emailed me to WeChat to urge the Spring series of articles to be updated.
It seems to continue to update the Spring article. After thinking about it, write an article about annotations in Spring, because the previous articles in the Spring series have been updating Spring annotation-driven development. This article can be regarded as a small summary of the previous article. It is estimated that after updating this article, we will enter the update of Spring's AOP chapter.
have not read other Spring articles can read it in the topic [160c88f47984e9 Spring series
The article has been included in:
https://github.com/sunshinelyz/technology-binghe
https://gitee.com/binghe001/technology-binghe
xml configuration and class configuration
1.xml configuration
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/sp
<bean id="person" class="com.binghe.spring.Person"></bean>
</beans>
Get the Person instance as shown below.
public static void main( String[] args ){
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
System.out.println(ctx.getBean("person"));
}
2. Class configuration
@Configuration
public class MainConfig {
@Bean
public Person person(){
return new Person();
}
}
Here, there is one thing to pay attention to: if it is used in the form of @Bean, the default name of the bean is the method name, if @Bean(value="bean's name") then the bean name is specified.
Get the Person instance as shown below.
public static void main( String[] args ){
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(MainConfig.class);
System.out.println(ctx.getBean("person"));
}
@CompentScan annotation
We can use the @CompentScan annotation to perform package scanning, as shown below.
@Configuration
@ComponentScan(basePackages = {"com.binghe.spring"})
public class MainConfig {
}
excludeFilters attribute
When we use the @CompentScan annotation to scan, we can use the excludeFilters attribute of the @CompentScan annotation to exclude certain classes, as shown below.
@Configuration
@ComponentScan(basePackages = {"com.binghe.spring"},excludeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION,value = {Controller.class}),
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,value = {PersonService.class})
})
public class MainConfig {
}
includeFilters attribute
When we use the @CompentScan annotation to scan, we can use the includeFilters attribute of the @CompentScan annotation to include certain classes. Note here: you need to set the useDefaultFilters property to false (true means scan all)
@Configuration
@ComponentScan(basePackages = {"com.binghe.spring"},includeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION,value = {Controller.class, PersonService.class})
},useDefaultFilters = false)
public class MainConfig {
}
@ComponentScan.Filter type
- Annotated FilterType.ANNOTATION @Controller @Service @Repository @Compent
- Specify the type of FilterType.ASSIGNABLE_TYPE @ComponentScan.Filter(type =FilterType.ASSIGNABLE_TYPE,value = {Person.class})
- FilterType.ASPECTJ of aspectj type (not commonly used)
- FilterType.REGEX of regular expressions (not commonly used)
- Custom FilterType.CUSTOM
public enum FilterType {
//注解形式 比如@Controller @Service @Repository @Compent
ANNOTATION,
//指定的类型
ASSIGNABLE_TYPE,
//aspectJ形式的
ASPECTJ,
//正则表达式的
REGEX,
//自定义的
CUSTOM
}
FilterType.CUSTOM custom type
public class CustomFilterType implements TypeFilter {
@Override
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
//获取当前类的注解源信息
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
//获取当前类的class的源信息
ClassMetadata classMetadata = metadataReader.getClassMetadata();
//获取当前类的资源信息
Resource resource = metadataReader.getResource();
return classMetadata.getClassName().contains("Service");
}
@ComponentScan(basePackages = {"com.binghe.spring"},includeFilters = {
@ComponentScan.Filter(type = FilterType.CUSTOM,value = CustomFilterType.class)
},useDefaultFilters = false)
public class MainConfig {
}
Configure Bean's scope object
Don't specify @Scope
Without specifying @Scope, all beans are single-instance beans, and they are loaded by the hungry man (the instance is created when the container starts)
@Bean
public Person person() {
return new Person();
}
@Scope is prototype
Specifying @Scope as prototype means that it is multi-instance, and it is loaded in lazy mode (when the IOC container is started, the object will not be created, but will be created when it is used for the first time)
@Bean
@Scope(value = "prototype")
public Person person() {
return new Person();
}
@Scope value
- singleton single instance (default)
- prototype multi-instance
- request the same request
- session the same session level
Lazy loading
Bean lazy loading @Lazy (mainly for the single-instance bean container when it starts, the object is not created, and the object is created when it is used for the first time)
@Bean
@Lazy
public Person person() {
return new Person();
}
@Conditional condition judgment
In the scenario, there are two components, CustomAspect and CustomLog. My CustomLog component is dependent on CustomAspect
Application: Create a CustomCondition class to implement the Condition interface
public class CustomCondition implements Condition {
/****
@param context
* @param metadata
* @return
*/
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
//判断容器中是否有CustomAspect的组件
return context.getBeanFactory().containsBean("customAspect");
}
}
public class MainConfig {
@Bean
public CustomAspect customAspect() {
return new CustomAspect();
}
@Bean
@Conditional(value = CustomCondition.class)
public CustomLog customLog() {
return new CustomLog();
}
}
Add components to the IOC container
(1) Via @CompentScan +@Controller @Service @Respository @compent. Applicable scenarios: Components written for ourselves can be loaded into the container in this way.
(2) Import components through @Bean (suitable for importing third-party component classes)
(3) Import the component through @Import (the id of the imported component is the path of the full class name)
@Configuration
@Import(value = {Person.class})
public class MainConfig {
}
Import components through @Import's ImportSeletor class (the id of the imported component is the full class name path)
public class CustomImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{"com.binghe.spring"};
}
}
Configuration
@Import(value = {Person.class}
public class MainConfig {
}
Import components through @Import's ImportBeanDefinitionRegister (you can specify the name of the bean)
public class DogBeanDefinitionRegister implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
//创建一个bean定义对象
RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(Dog.class);
//把bean定义对象导入到容器中
registry.registerBeanDefinition("dog",rootBeanDefinition);
}
}
@Configuration
@Import(value = {Person.class, Car.class, CustomImportSelector.class, DogBeanDefinitionRegister.class})
public class MainConfig {
}
Realize the registered component by implementing the FacotryBean interface
public class CarFactoryBean implements FactoryBean<Car> {
@Override
public Car getObject() throws Exception {
return new Car();
}
@Override
public Class<?> getObjectType() {
return Car.class;
}
@Override
public boolean isSingleton() {
return true;
}
}
Bean initialization and destruction
Specify the bean initialization method and bean destruction method
The life cycle of the Bean is managed by the container, and we can specify the initialization method and the destruction method of the bean by ourselves
@Configuration
public class MainConfig {
//指定了bean的生命周期的初始化方法和销毁方法.@Bean(initMethod = "init",destroyMethod = "destroy")
public Car car() {
return new Car();
}
}
For single-instance beans, when the container starts, the bean object is created, and when the container is destroyed, the bean destruction method will also be called
For multi-instance beans, when the container is started, the bean will not be created but when the bean is obtained, and the destruction of the bean is not managed by the IOC container
Realized by InitializingBean and DisposableBean
Implement bean initialization and destruction methods through the InitializingBean and DisposableBean interfaces
@Component
public class Person implements InitializingBean,DisposableBean {
public Person() {
System.out.println("Person的构造方法");
}
@Override
public void destroy() throws Exception {
System.out.println("DisposableBean的destroy()方法 ");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("InitializingBean的 afterPropertiesSet方法");
}
}
Pass JSR250 specification
Methods annotated by @PostConstruct and @ProDestory provided by the JSR250 specification
@Component
public class Book {
public Book() {
System.out.println("book 的构造方法");
}
@PostConstruct
public void init() {
System.out.println("book 的PostConstruct标志的方法");
}
@PreDestroy
public void destory() {
System.out.println("book 的PreDestory标注的方法");
}
}
Realized by BeanPostProcessor
The post processor of the bean through Spring's BeanPostProcessor will intercept all bean creation processes
- postProcessBeforeInitialization is called before the init method
- postProcessAfterInitialization is called after the init method
@Component
public class CustomBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("CustomBeanPostProcessor...postProcessBeforeInitialization:"+beanName);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("CustomBeanPostProcessor...postProcessAfterInitialization:"+beanName);
return bean;
}
}
BeanPostProcessor execution timing
populateBean(beanName, mbd, instanceWrapper)
initializeBean{
applyBeanPostProcessorsBeforeInitialization()
invokeInitMethods{
isInitializingBean.afterPropertiesSet()
自定义的init方法
}
applyBeanPostProcessorsAfterInitialization()方法
}
Assign values to components through @Value + @PropertySource
public class Person {
//通过普通的方式
@Value("独孤")
private String firstName;
//spel方式来赋值
@Value("#{28-8}")
private Integer age;
通过读取外部配置文件的值
@Value("${person.lastName}")
private String lastName;
}
@Configuration
@PropertySource(value = {"classpath:person.properties"}) //指定外部文件的位置
public class MainConfig {
@Bean
public Person person() {
return new Person();
}
}
Automatic assembly
Use of @AutoWired
Automatic injection
@Repository
public class CustomDao {
}
@Service
public class CustomService {
@Autowired
private CustomDao customDao;
}
in conclusion:
(1) The automatic assembly is first assembled according to the type. If multiple components of the same type are found in the IOC container, then the assembly is carried out according to the attribute name
@Autowired
private CustomDao customDao;
For example, there are two CustomDao type components in my container, one is called CustomDao and the other is called CustomDao2. Then we use @AutoWired to modify the attribute name of CustomDao, then load the CustomDao component of the container, if the attribute name is tuligDao2, then he loads it When the CustomDao2 component
(2) Assuming that we need to specify specific components for assembly, we can specify the assembly components by using @Qualifier("CustomDao")
Or add @Primary annotation to @Bean on the configuration class
@Autowired
@Qualifier("CustomDao")
private CustomDao customDao2
(3) Assuming that there is no CustomDao and CustomDao2 in our container, then an exception will be thrown during assembly
No qualifying bean of type 'com.binghhe.spring.dao.CustomDao' available
If we don’t want to throw exceptions, we need to specify required to be false.
@Autowired(required = false)
@Qualifier("customDao")
private CustomDao CustomDao2;
(4) @Resource (JSR250 specification)
The function is almost the same as that of @AutoWired, but does not support the support of @Primary and @Qualifier
(5) @InJect (JSR330 specification)
Need to import jar package dependency, function and support @Primary function, but there is no function of Require=false
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
(6) Use @Autowired to mark the method
- Marked on the set method
//@Autowired
public void setCustomLog(CustomLog customLog) {
this.customLog = customLog;
}
- Marked on the construction method
@Autowired
public CustomAspect(CustomLog customLog) {
this.customLog = customLog;
}
marked in the input parameters of the configuration class (you don’t need to write)
@Bean
public CustomAspect CustomAspect(@Autowired CustomLog customLog) {
CustomAspect customAspect = new CustomAspect(customLog);
return ustomAspect;
}
XXXAwarce interface
When our own components need to use the underlying components of spring ioc, such as ApplicationContext, we can achieve this by implementing the XXXAware interface
@Component
public class CustomCompent implements ApplicationContextAware,BeanNameAware {
private ApplicationContext applicationContext;
@Override
public void setBeanName(String name) {
System.out.println("current bean name is :【"+name+"】");
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
@Profile annotation
Use @Profile annotation to activate and identify different beans according to the environment
- @Profile is marked on the class, then the entire configuration class will take effect only if the current environment matches
- @Profile is marked on the Bean, then only the Bean in the current environment will be activated
- Beans that are not marked as @Profile can be activated in any environment
@Configuration
@PropertySource(value = {"classpath:ds.properties"})
public class MainConfig implements EmbeddedValueResolverAware {
@Value("${ds.username}")
private String userName;
@Value("${ds.password}")
private String password;
private String jdbcUrl;
private String classDriver;
@Override
public void setEmbeddedValueResolver(StringValueResolver resolver) {
this.jdbcUrl = resolver.resolveStringValue("${ds.jdbcUrl}");
this.classDriver = resolver.resolveStringValue("${ds.classDriver}");
}
@Bean
@Profile(value = "test")
public DataSource testDs() {
return buliderDataSource(new DruidDataSource());
}
@Bean
@Profile(value = "dev")
public DataSource devDs() {
return buliderDataSource(new DruidDataSource());
}
@Bean
@Profile(value = "prod")
public DataSource prodDs() {
return buliderDataSource(new DruidDataSource());
}
private DataSource buliderDataSource(DruidDataSource dataSource) {
dataSource.setUsername(userName);
dataSource.setPassword(password);
dataSource.setDriverClassName(classDriver);
dataSource.setUrl(jdbcUrl);
return dataSource;
}
}
Activate the method of switching environment
(1) Switch jvm parameters at runtime
-Dspring.profiles.active=test|dev|prod
(2) Activate by means of code
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.getEnvironment().setActiveProfiles("test","dev");
ctx.register(MainConfig.class);
ctx.refresh();
printBeanName(ctx);
}
here today. I’m Glacier. If you have any questions, you can leave a message below,
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。