@Configuration configure spring and start the spring container
@Configuration is used to define the configuration class, which is labeled on the class, which is equivalent to < beans > in the xml configuration file of spring. Its function is to configure the spring container (application context)
Example description:
Configuration class
@Configuration public class MyConfig { public MyConfig() { System.out.println("TestConfig Container initialization!!!!"); } }
Equivalent to xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> </beans>
Test class
public class TestConfig { @Test public void test(){ AnnotationConfigApplicationContext applicationContext=new AnnotationConfigApplicationContext(MyConfig.class); } }
Operation results
TestConfig container initialization!!!!
@ Configuration&@Bean Register components in container
@Bean is marked in method, which is equivalent to < / bean > in xml configuration configuration
Code example description:
Registration class
public class ConfigurationBean { public void start() { System.out.println("Start container initialization!!!!!"); } }
Configuration class
@Configuration public class MyConfiguration { //You can specify the name of the bean or the method loaded before the container is injected @Bean() public ConfigurationBean configurationBean(){ return new ConfigurationBean(); } }
Equivalent to xml
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="configurationBean" class="zfcoding.bean.ConfigurationBean" ></bean> </beans>
test method
@Test public void ConfigurationTest(){ AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfiguration.class); ConfigurationBean configurationBean=(ConfigurationBean) applicationContext.getBean("configurationBean"); System.out.println(configurationBean); }
Operation result:
Start container initialization!!!!!
zfcoding.bean.ConfigurationBean@77be656f
Explain:
(1) The @ bean annotation is marked on the method. If the bean name is not specified through @ bean, the method name is the same by default;
(2) The @ bean annotation is marked on the method. If you want to specify the bean name through @ bean, for example, @ bean ("configurationbean 1"), the name of the instantiated bean in the container is configurationbean 1;
@Bean specifies the method of initialization and destruction and @ Scope, @ Lazy
Life cycle of container bean Management:
We can customize the initialization and destruction methods. The container calls our customized initialization and destruction methods when the bean is in the current life cycle.
@The initialization and destruction methods are specified in the Bean.
@Bean(initMethod = "init",destroyMethod = "destory")
xml
<bean id="student" class="zfcoding.bean.Student" init-method="init" destroy-method="destory"></bean>
@Scope
By default: singleton single instance (the default), ioc container startup will call methods to create objects and put them into ioc container. Get the object directly every time later.
prototype: multi instance, ioc container startup does not call methods to create objects in the container. Instead, the method is called to create the object every time it is acquired, and the object is created once.
@Lazy loading,
For single instance bean s, objects are created by default when the container is started
Lazy loading: the container starts the non creation key object, creates the object with Bean for the first time, and initializes it.
Example description:
public class Student { public Student() { System.out.println("Student Container loading starts!!!!"); } //The object is created and assigned. Call the initialization method public void init() { System.out.println("Student.init()Initialization start....."); } //Destroy is called when the container is closed for (single instance). //Multi instance (@ Scope("prototype"): the container will not manage this bean, and the container will not call back the destroyed method. public void destory() { System.out.println("Student.destory()........."); } }
@Configuration public class MyConfigStudent { //@Lazy //@Scope("prototype") @Bean(value = "student",initMethod = "init",destroyMethod = "destory") public Student student(){ return new Student(); } }
Test class I
public class MyConfigStudentTest { @Test public void test(){ AnnotationConfigApplicationContext applicationContext=new AnnotationConfigApplicationContext(MyConfigStudent.class); } }
Operation results
Student container loading started!!!!
Student.init() initialization start
Then, the ioc container startup will call methods to create objects and put them into the ioc container. Get the object directly every time later.
If we use @ Lazy annotation (single instance), the container starts the non creation key object, and the test result has no output information.
Test class 2. For the first time, we use Bean to create objects and initialize them
public class MyConfigStudentTest { @Test public void test(){ AnnotationConfigApplicationContext applicationContext=new AnnotationConfigApplicationContext(MyConfigStudent.class); Student student = (Student)applicationContext.getBean("student"); System.out.println(student); applicationContext.close(); } }
Operation results
Student Container loading starts!!!! Student.init()Initialization start..... zfcoding.bean.Student@7364985f Student.destory().........
Lazy load (@ lazy): when the container starts, it does not create key objects, but creates objects with Bean for the first time and initializes them.
InitializingBean and DisposableBean
The InitializingBean interface provides a way for beans to initialize methods. It only includes the afterpropertieset method. Any class that inherits this interface will execute this method when initializing beans.
Test class
public class TestInitializingBean implements InitializingBean { public void afterPropertiesSet() throws Exception { System.out.println("TestInitializingBean.afterPropertiesSet()......"); } public void init() { System.out.println("TestInitializingBean.init()......."); } }
Configuration class
@Configuration public class MyInitializingBeanConfig { @Bean(value = "testInitializingBean",initMethod = "init") public TestInitializingBean testInitializingBean(){ return new TestInitializingBean(); } }
Test class
public class TestnitializingBeanConfig { @Test public void test(){ AnnotationConfigApplicationContext applicationContext=new AnnotationConfigApplicationContext(MyInitializingBeanConfig.class); } }
Operation result:
TestInitializingBean.afterPropertiesSet()......
TestInitializingBean.init().......
It can be seen from the results that when Spring initializes a bean, if the bean implements the InitializingBean interface and specifies init method in the configuration file, the system calls the afterPropertieSet() method first, and then the method specified in init method.
How is this method implemented in spring? Check the invokeInitMethods() in the spring load bean's source class AbstractAutowiredCapableBeanFactory class, as follows:
protected void invokeInitMethods(String beanName, final Object bean, RootBeanDefinition mbd) throws Throwable { //Determine whether the bean implements the InitializingBean interface. If the InitializingBean interface is implemented, only the afterPropertiesSet method of the bean will be called boolean isInitializingBean = (bean instanceof InitializingBean); if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) { if (logger.isDebugEnabled()) { logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'"); } if (System.getSecurityManager() != null) { try { AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() { @Override public Object run() throws Exception { ((InitializingBean) bean).afterPropertiesSet(); return null; } }, getAccessControlContext()); } catch (PrivilegedActionException pae) { throw pae.getException(); } } else { ((InitializingBean) bean).afterPropertiesSet(); } } if (mbd != null) { String initMethodName = mbd.getInitMethodName(); if (initMethodName != null && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) && !mbd.isExternallyManagedInitMethod(initMethodName)) { invokeCustomInitMethod(beanName, bean, mbd); } } }
Summary:
Spring provides two ways to initialize beans. One is to implement the InitializingBean interface and override the afterpropertieset method. The other is to specify it in the configuration file through init method, but if it is specified at the same time, the method implemented by InitializingBean is called first.
@PostConstruct and @ PreDestroy
have access to JS250,@PostConstruct Mark on the method, the bean is created and the property assignment is completed to execute the initialization method
@PreDestroy, inform us to clean up before the container destroys bean s
@ ComponentScan&@Configuration Register components with container
@ Configuration+@ComponentScan Inject Component, just annotate @ Controller, @ Service, @ Repository, @ Component into Spring container
xml configuration
<context:component-scan base-package="zfcoding"></context:component-scan>
Code example description:
Classes to inject
@Component public class PersonComponent { } @Repository public class PersonDao { } @Service public class PersonService { } @Controller public class PersonController { }
Configuration class
@Configuration //@ComponentScan(basePackages = "zfcoding", //// includeFilters =@ComponentScan.Filter(type=FilterType.ANNOTATION,classes = Controller.class),useDefaultFilters=false ) @ComponentScan(basePackages = "zfcoding", excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Controller.class, Service.class})) public class MyCompoentScan { }
Test method
@Test public void ComponentSanTest(){ AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyCompoentScan.class); String[] definitionNames = applicationContext.getBeanDefinitionNames(); for (String definitionName:definitionNames){ System.out.println(definitionName); } }
Operation results
org.springframework.context.annotation.internalConfigurationAnnotationProcessor org.springframework.context.annotation.internalAutowiredAnnotationProcessor org.springframework.context.annotation.internalRequiredAnnotationProcessor org.springframework.context.annotation.internalCommonAnnotationProcessor org.springframework.context.event.internalEventListenerProcessor org.springframework.context.event.internalEventListenerFactory myCompoentScan personComponent personDao
explain:
excludeFilters exclude components that do not need to be loaded
includeFilters only contain components that need to be loaded. When using them, useDefaultFilters=false to take effect
@ ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Controller.class, Service.class }), excluding the annotation annotation annotation of @ controller and @ service classes.
@Conditional - set component scope
Judge according to certain conditions, and register bean s in the container according to the conditions
To customize Conditional conditions, you need to write a class that implements the Condition interface. We can directly use @ Conditional({WindowsEnvironment.class }
@Conditional can be defined on both methods and classes. Code implementation of custom conditions requires the implementation of Condition interface
Conditional class
public class WindowsEnvironment implements Condition { public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { Environment environment = context.getEnvironment(); String property = environment.getProperty("os.name"); BeanDefinitionRegistry registry = context.getRegistry(); if(property.contains("Windows 10")){ return true; } return false; } }
public class LiunxEnvironment implements Condition { public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { Environment environment = context.getEnvironment(); if (environment.containsProperty("Liunx")){ return true; } return false; } }
Configuration class
@Configuration public class MyCondition { @Conditional({WindowsEnvironment.class}) @Bean public ConfigurationBean configurationBean(){ return new ConfigurationBean("Zhang San"); } @@Conditional({LiunxEnvironment.class}) @Bean public ConfigurationBean configurationBean1(){ return new ConfigurationBean("Li Si"); } }
test method
public class CoditionTest { @Test public void test(){ AnnotationConfigApplicationContext applicationContext=new AnnotationConfigApplicationContext(MyCondition.class); String[] beanNamesForType = applicationContext.getBeanNamesForType(ConfigurationBean.class); for (String s:beanNamesForType){ System.out.println(s); } } }
Operation results
configurationBean
@Import quickly import a component to a container
1. @ import (the component to be imported), the container will automatically register this component, and the default id is the full class name.
2. ImportSelector, the custom logic returns the classology written by the component to be imported to implement the ImportSelector interface, and returns the full class name array of the primary key to be imported.
3. Importbeandefinitionregister. For custom logic, you need to write a class to implement the importbeandefinitionregister interface, and register the beans into the container manually.
Code instance
public class Red { } public class Blue { }
// @Import({Red.class,MyImportSelector.class,MyImportBeanDefinitionRegistrar.class}) public class MyImport { }
public class MyImportSelector implements ImportSelector { //AnnotationMetadata: all annotation information of the current annotation @ Import annotation class //Returns the full class name of the class public String[] selectImports(AnnotationMetadata importingClassMetadata) { return new String[]{"zfcoding.bean.Blue"}; } }
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar { //importingClassMetadata: annotation information of the current class //Beandefinitionregistry beandefinition register class to add all beans to the container, be anDefinitionRegistry.registerBeanDefinition Manual registration public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { boolean red = registry.containsBeanDefinition("zfcoding.bean.Red"); if (red){ RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(Blue.class); registry.registerBeanDefinition("blue",rootBeanDefinition); } } }
Test class
public class ImportTest { @Test public void test(){ AnnotationConfigApplicationContext applicationContext=new AnnotationConfigApplicationContext(MyImport.class); String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames(); for (String s:beanDefinitionNames){ System.out.println(s); } } }
Operation results
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactorymyImport
zfcoding.bean.Red
zfcoding.bean.Blue
blue
Summary:
To import components into a container:
1,@ Configuration&@Bean Register components in container
2,@ComponentScan&@Configuration(@Controller ,@Service, @Repository, @Component)
3, @ Import quickly imports a component to the container
@Value assignment and @ PropertySource load external configuration file
@Value
1. Basic value
2,SPEL #{}
3. You can write ${} to the value in the configuration file (the value in the running environment)
Use @ PropertySource to get the value in the external configuration file and save it to the running environment. After loading the final configuration file, use ${} to extract the values in the configuration file
Code instance:
The code omits the setter(),getter(),toString() method.
public class Person { @Value("Zhang San") private String name; @Value("#{20-1}") private Integer age; @Value("${person.sex}") private String sex; }
//<context:property-placeholder location="person.properties"></context:property-placeholder> @PropertySource("classpath:person.properties") @Configuration public class MyConfigValue { @Bean public Person person(){ return new Person(); } }
person.properties
person.sex=1
Test class
@Test public void test1(){ AnnotationConfigApplicationContext applicationContext=new AnnotationConfigApplicationContext(MyConfigValue.class); Person person = (Person) applicationContext.getBean("person"); System.out.println(person); }
Operation results
Person{name='Zhang San', age=19, sex='1'}
@Autowired &@Qualifier&@Primary
Automatic assembly:
@Autowired auto injection, a single default priority is to find the corresponding component in the container according to the type. By default, the property must be assigned well. If not found, an error will be reported. You can use @ Autowired (required=false), which is not necessary;
@Qualifier, which specifies the component id to be assembled;
@When Primary allows Spring to automatically assemble, you can use @ Qualifier to specify the name of the bean to be assembled
@Resource &@Inject
Spring also supports @ Resource (JSR250) and @ Inject (JSR330) {java specification annotations}
@Resource and @ Autowired implement the same function of automatic assembly. By default, they are assembled according to the name of the component.
@Inject needs to be imported javax.inject The package of is the same as the @ Autowired function, without the function of required=false.
@Profile environment construction
Spring provides us with the ability to dynamically activate and switch a series of components according to the current environment
Let's use the data source to illustrate this problem:
@Profile specifies which environment can be registered in the container. With @ profile added, only when this environment is activated can it be registered in the spring container. The default is defalut
Code instance:
@PropertySource("classpath:db.properties") @Configuration public class MyConfigProfile implements EmbeddedValueResolverAware { @Value("${db.username}") private String username; @Value("${db.password=}") private String password; private StringValueResolver stringValueResolver; private String driveClass; @Profile("default") @Bean("testDataSource") public DataSource dataSource() throws PropertyVetoException { ComboPooledDataSource dataSource=new ComboPooledDataSource(); dataSource.setUser(username); dataSource.setPassword(password); dataSource.setJdbcUrl("jdbc:mysql://127.0.0.1:3306/springboot?serverTimezone=UTC&useSSL=false&autoReconnect=true&tinyInt1isBit=false&useUnicode=true&characterEncoding=utf8"); dataSource.setDriverClass(driveClass); return dataSource; } @Profile("dev") @Bean("devDataSource") public DataSource devDataSource() throws PropertyVetoException { ComboPooledDataSource dataSource=new ComboPooledDataSource(); dataSource.setUser(username); dataSource.setPassword(password); dataSource.setJdbcUrl("jdbc:mysql://127.0.0.1:3306/springboot?serverTimezone=UTC&useSSL=false&autoReconnect=true&tinyInt1isBit=false&useUnicode=true&characterEncoding=utf8"); dataSource.setDriverClass(driveClass); return dataSource; } public void setEmbeddedValueResolver(StringValueResolver resolver) { this.stringValueResolver=resolver; driveClass = stringValueResolver.resolveStringValue("db.driverClass"); } }
db.properties
db.username=root db.password=root db.driverClass=com.mysql.jdbc.Driver
Test code:
public class DataSourceProfileTest { @Test public void test() { AnnotationConfigApplicationContext applicationContext=new AnnotationConfigApplicationContext(MyConfigProfile.class); String[] beanNamesForType = applicationContext.getBeanNamesForType(DataSource.class); for (String s:beanNamesForType){ System.out.println(s); } } /* Using a parameterless constructor * Set up the active environment * Register main configuration class * Start refresh container */ @Test public void test1(){ //Using a parameterless constructor AnnotationConfigApplicationContext applicationContext=new AnnotationConfigApplicationContext(); //Set up the active environment applicationContext.getEnvironment().setActiveProfiles("dev"); //Register main configuration class applicationContext.register(MyConfigProfile.class); //Start refresh container applicationContext.refresh(); String[] beanNamesForType = applicationContext.getBeanNamesForType(DataSource.class); for (String s:beanNamesForType){ System.out.println(s); } } }
Test case run results
testDataSource
devDataSource
Summary:
@The Profile can also be marked on the class to indicate that the configuration in the entire configuration file can take effect only when the environment is specified. Beans without environment representation are loaded in any environment (provided that the configuration class is valid). You can also use command line parameters:- Dspring.profiles.active=test Activate the corresponding environment.
I am AFP, the author of the official account of "AFP chat programming". I am a learning enthusiast for back-end technology. I will update JAVA technical articles regularly, and encourage me on the way forward.
Welcome to my official account, back 666, receive benefits, you know.