GitHub 3.7K Star Java engineers become god’s way, not to know?
GitHub 3.7K Star Java engineers become god’s way, really not to know?
GitHub 3.7K Star Java engineer becomes god’s way, really sure not to check out?
Most Spring projects now use annotation-based Configuration, using @Configuration instead of tags. A single line of comment can do a lot of things. But there’s a lot to learn and think about behind each of these notes. These are some of the questions that interviewers like to ask.
In an interview about Spring annotations, you might experience the interviewer asking you a killer question:
What does @Configuration do? What is the difference between @Configuration and XML? What kind of good? How does Spring get the Bean definition based on? What’s the difference between @Autowired, @Inject, and @Resource? @Value, @propertysource and @Configuration? How does Spring handle classes with @configuration@import? What does @profile do? How is @Configuration nested? How does Spring lazily initialize beans? How do Spring projects unit test? What are the restrictions on using @Configuration?
This article will try to answer the above questions. Take a quick look at the @Configuration annotation and see how it works and interacts with other annotations. Article content is long, suggested collection.
@Configuration Basic description
** Definition: Instructs a class to declare one or more @Bean declared methods and is managed uniformly by the Spring container to generate Bean definitions and service requested classes for these beans at run time. * * such as:
@Configuration
public class AppConfig {
@Bean
public MyBean myBean(a){
return newMyBean(); }}Copy the code
AppConfig adds the @Configuration annotation to indicate that this is a Configuration class. There is a myBean() method that returns an instance of myBean() and is annotated with @bean to indicate that the method is the Bean that needs to be managed by Spring. If @bean does not specify a name, the default is to use the myBean name, which is lowercase.
Start with comments:
By starting a AnnotationConfigApplicationContext to guide this @ Configuration annotation class, such as:
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(AppConfig.class);
ctx.refresh();
Copy the code
In the web project, also can use AnnotationContextWebApplicationContext or other variants to start.
Create a new SpringBoot project (don’t ask me why, it’s faster to create projects that way).
- The pom.xml file is as follows:
<?xml version="1.0" encoding="UTF-8"? >
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.5. RELEASE</version>
<relativePath/> <! -- lookup parent from repository -->
</parent>
<groupId>com.spring.configuration</groupId>
<artifactId>spring-configuration</artifactId>
<version>0.0.1 - the SNAPSHOT</version>
<name>spring-configuration</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.6. RELEASE</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Copy the code
- Create a new MyConfiguration environment configuration under the config package, similar to the code in the example above. The complete code is as follows:
@Configuration
public class MyConfiguration {
@Bean
public MyBean myBean(a){
System.out.println("myBean Initialized");
return newMyBean(); }}Copy the code
MyConfiguration is a configuration class that can be declared to manage multiple beans under this class. We declare a Bean of MyBean and expect it to be loaded and managed by the container.
- Create a new MyBean class under the POJO package as follows
public class MyBean {
public MyBean(a){
System.out.println("generate MyBean Instance");
}
public void init(a){
System.out.println("MyBean Resources Initialized"); }}Copy the code
- Create a new SpringConfigurationApplication class, used to test MyConfiguration class, specific code is as follows:
public class SpringConfigurationApplication {
public static void main(String[] args) {
// AnnotationConfigApplicationContext context = = new AnnotationConfigApplicationContext(MyConfiguration.class)
/ / because we loaded @ the Configuration is based on the comments form, so you need to create AnnotationConfigApplicationContext
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
// Register MyConfiguration and refresh the bean container.context.register(MyConfiguration.class); context.refresh(); }}Copy the code
Output:
myBean Initialized generate MyBean Instance
As you can see from the output, the bean with the default name myBean is loaded as the container is loaded, and since the myBean method returns a constructor of myBean, myBean is initialized.
Start using XML
- Can be defined using XML
<context:annotation-config />
To enable annotation-based startup, define a MyConfiguration bean and create a new application-context. XML file under /resources:
<?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"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="Http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd"
>
<! - the equivalent of AnnotationConfigApplicationContext annotation-based start class -- >
<context:annotation-config />
<bean class="com.spring.configuration.config.MyConfiguration"/>
</beans>
Copy the code
- Need to introduce applicationContext. XML in SpringConfigurationApplication need to be introduced, modified SpringConfigurationApplication is as follows:
public class SpringConfigurationApplication {
public static void main(String[] args) {
ApplicationContext context =
new ClassPathXmlApplicationContext("applicationContext.xml"); }}Copy the code
Output:
myBean Initialized generate MyBean Instance
Get the Bean definition based on ComponentScan()
@Configuration uses @Component as the original annotation, so the @Configuration class can also be scanned by components (especially using the XML Context: Component-scan element).
Here are some annotations: @controller, @Service, @Repository, @Component
-
Controller: The class that indicates an annotation is a “Controller”, that is, a Controller, which can be thought of as the Controller role of MVC pattern. This annotation is a special @Component that allows the implementation class to be scanned through the classpath. It is usually used with the @requestMapping annotation.
-
@service: indicates that the annotated class is a “Service”, i.e. the Service layer, which can be thought of as the Service layer in the MVC pattern. The annotation is also a special @Component that allows the implementation class to be scanned through the classpath
-
@Repository: The annotation class is a “Repository”, and the team implemented JavaEE patterns such as a “Data Access Object” that could be used as a DAO. When combined with PersistenceExceptionTranslationPostProcessor to use this annotation class are eligible for the purpose of the Spring conversion. This annotation is also a special implementation of @Component that allows the implementation class to be scanned automatically
-
@Component: Indicates that the annotation class is a Component that is considered a candidate for automatic detection when annotation-based configuration and classpath scanning are used.
For example, if you want to define a Service class and want it to be managed by Spring, you can use the following annotations: You should call it @Service instead of @Controller because semantically @Service is more like a Service class than a Controller class, @Component is usually called a Component, and it can tag any class that you don’t specify strictly, like a configuration class, It doesn’t belong to any layer of the MVC pattern, so you’re more used to defining it as @Component. The @controller, @service, and @repository annotations all have @Component, so all three annotations can be replaced with @Component.
Take a look at the code to understand:
- Define five classes labeled with @Controller, @Service, @Repository, @Component, and @Configuration as follows
@Component
public class UserBean {}
@Configuration
public class UserConfiguration {}
@Controller
public class UserController {}
@Repository
public class UserDao {}
@Service
public class UserService {}
Copy the code
- in
MyConfiguration
The @ComponentScan annotation is applied to scan the package locations of the above five classes. The code is as follows:
@Configuration
@ComponentScan(basePackages = "com.spring.configuration.pojo")
public class MyConfiguration {
@Bean
public MyBean myBean(a){
System.out.println("myBean Initialized");
return newMyBean(); }}Copy the code
- Modify the code SpringConfigurationApplication, as follows:
public class SpringConfigurationApplication {
public static void main(String[] args) {
// AnnotationConfigApplicationContext context = = new AnnotationConfigApplicationContext(MyConfiguration.class)
// ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(MyConfiguration.class);
context.refresh();
// Get the name of the bean definition during startup
for(String str : context.getBeanDefinitionNames()){
System.out.println("str = "+ str); } context.close(); }}Copy the code
Output:
myBean Initialized generate MyBean Instance str = org.springframework.context.annotation.internalConfigurationAnnotationProcessor str = org.springframework.context.annotation.internalAutowiredAnnotationProcessor str = org.springframework.context.annotation.internalRequiredAnnotationProcessor str = org.springframework.context.annotation.internalCommonAnnotationProcessor str = org.springframework.context.event.internalEventListenerProcessor str = org.springframework.context.event.internalEventListenerFactory str = myConfiguration str = userBean str = userConfiguration str = userController str = userDao str = userService str = myBean
As you can clearly see from the output, the five classes defined above are successfully scanned by @ComponentScan and loaded at application startup.
@ the Configuration and the Environment
@configuration is usually used with Environment. Properties parsed by @environment reside in one or more “PropertySource” objects. The @configuration class can use @propertysource, Provide a source of attributes like the Environment object
- For testing purposes, we have introduced junit4 and Spring-test dependencies. The complete configuration file is shown below
<?xml version="1.0" encoding="UTF-8"? >
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.5. RELEASE</version>
<relativePath/> <! -- lookup parent from repository -->
</parent>
<groupId>com.spring.configuration</groupId>
<artifactId>spring-configuration</artifactId>
<version>0.0.1 - the SNAPSHOT</version>
<name>spring-configuration</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring.version>5.0.6. RELEASE</spring.version>
<spring.test.version>4.3.13. RELEASE</spring.test.version>
<junit.version>4.12</junit.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.test.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Copy the code
- Define an EnvironmentConfig class in the config package and inject the Environment property as follows:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = EnvironmentConfig.class)
@Configuration
@PropertySource("classpath:beanName.properties")
public class EnvironmentConfig {
@Autowired
Environment env;
@Test
public void testReadProperty(a){
// Get the bean.name.controller property
System.out.println(env.getProperty("bean.name.controller"));
// Check whether bean.name.component is included
System.out.println(env.containsProperty("bean.name.component"));
// Returns the value of the attribute associated with the given key
System.out.println(env.getRequiredProperty("bean.name.service")); }}Copy the code
- Create a new beanname.properties file under /resources as follows:
bean.name.configuration=beanNameConfiguration
bean.name.controller=beanNameController
bean.name.service=beanNameService
bean.name.component=beanNameComponent
bean.name.repository=beanNameRepository
Copy the code
Start and run the Junit test with the following output:
… . … .
beanNameController
true
beanNameService
… . … .
The difference between @autowired, @Inject and @Resource
@ Inject: this is a new jsr330 specification, through AutowiredAnnotationBeanPostProcessor class implements the dependency injection. The javax.inject package is a Java built-in annotation.
@Inject
@Named("environment")
Environment env;
Copy the code
Without the @named annotation, you need to configure the same as the variable name.
@autowired: @autowired is provided by the Spring annotations, through AutowiredAnnotationBeanPostProessor class implements injection. Located in the org. Springframework. Beans. Factory. The annotation bags, is the annotations in the Spring
@Autowired
Environment env;
Copy the code
The default is byType injection
@ the Resource: @ the Resource is the implementation of the JSR specification, @ the Resource through CommonAnnotationBeanPostProcessor class implements injection. @resource typically specifies a name attribute, as follows:
@Resource(name = "environment")
Environment env;
Copy the code
The default is byName for injection
The difference between:
The @autowired and @ Inject basic is the same, because both are handled using AutowiredAnnotationBeanPostProcessor dependency injection. But @ the Resource is an exception, it USES CommonAnnotationBeanPostProcessor to handle the dependency injection. Of course, both are Beanpostprocessors.
After introducing the differences among the above three, the Environment attributes can be modified in the above injection mode
@Value, @propertysource, and @Configuration
@Configuration can be used with @Value and @propertysource to read external Configuration files as follows:
- Create a new one under the config package
ReadValueFromPropertySource
Class, code as follows
@PropertySource("classpath:beanName.properties")
@Configuration
public class ReadValueFromPropertySource {
@Value("bean.name.component")
String beanName;
@Bean("myTestBean")
public MyBean myBean(a){
return newMyBean(beanName); }}Copy the code
The configuration file introduced via @propertysource, which enables @Value to get property values, gives the myBean() method a name called myTestBean.
- Modify the MyBean class to add a name attribute and a constructor to reproduce its toString() method
public class MyBean {
String name;
public MyBean(String name) {
this.name = name;
}
public MyBean(a){
System.out.println("generate MyBean Instance");
}
public void init(a){
System.out.println("MyBean Resources Initialized");
}
@Override
public String toString(a) {
return "MyBean{" +
"name='" + name + '\' ' +
'} '; }}Copy the code
- Test in SpringConfigurationApplication, as follows
public class SpringConfigurationApplication {
public static void main(String[] args) {
// To show the integrity of the configuration file, the previous code is not deleted.
// AnnotationConfigApplicationContext context = = new AnnotationConfigApplicationContext(MyConfiguration.class)
// ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
// AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
// context.register(MyConfiguration.class);
// context.refresh();
//
// // gets the name of the bean definition during startup
// for(String str : context.getBeanDefinitionNames()){
// System.out.println("str = " + str);
/ /}
// context.close();
ApplicationContext context =
new AnnotationConfigApplicationContext(ReadValueFromPropertySource.class);
MyBean myBean = (MyBean) context.getBean("myTestBean");
System.out.println("myBean = "+ myBean); }}Copy the code
Using Applicatio@InConntext, you can get myTestBean and regenerate it into an instance of myBean.
Output: myBean = myBean {name=’bean.name.component’}
@ Import and @ Configuration
The @import definition (from JavaDoc) : Indicates that one or more Configuration class need to import, with equal function, in the Spring XML allows import @ the implementation of the Configuration, @ ImportSelector, @ ImportBeanDefinitionRegistar, Similar to AnnotationConfigApplicationContext and normal components. May be used at the class level or for raw annotations. Use @importResource if XML or other Bean resources other than @Configuration tags need to be imported. Here is a sample code:
- Create two new configuration classes under the POJO package, CustomerBo and SchedualBo
@Configuration
public class CustomerBo {
public void printMsg(String msg){
System.out.println("CustomerBo : " + msg);
}
@Bean
public CustomerBo testCustomerBo(a){
return newCustomerBo(); }}@Configuration
public class SchedulerBo {
public void printMsg(String msg){
System.out.println("SchedulerBo : " + msg);
}
@Bean
public SchedulerBo testSchedulerBo(a){
return newSchedulerBo(); }}Copy the code
- Create a new AppConfig under the Config package and import CustomerBo and SchedulerBo.
@Configuration
@Import(value = {CustomerBo.class,SchedulerBo.class})
public class AppConfig {}
Copy the code
- Create an ImportWithConfiguration under the config package to test the use of @import and @Configuration
public class ImportWithConfiguration {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
CustomerBo customerBo = (CustomerBo) context.getBean("testCustomerBo");
customerBo.printMsg("System out println('get from customerBo')");
SchedulerBo schedulerBo = (SchedulerBo) context.getBean("testSchedulerBo");
schedulerBo.printMsg("System out println('get from schedulerBo')"); }}Copy the code
Output:
CustomerBo : System out println(‘get from customerBo’) SchedulerBo : System out println(‘get from schedulerBo’)
@Profile
@profile: indicates that a component can be registered if one or more profiles specified by @Value are available.
There are three Settings:
-
Can pass ConfigurableEnvironment. SetActiveProfiles () programmatically activation
-
Can pass AbstractEnvironment. ACTIVE_PROFILES_PROPERTY_NAME (spring. Profiles. The active) attribute is set to
The JVM properties
-
As an environment variable, or as a Servlet context parameter for a web.xml application. Profiles can also be activated declaratively in integration tests through the @ActiveProfiles annotation.
scope
-
Class-level annotations in any class or directly associated with @Component, including the @Configuration class
-
As original annotations, you can customize annotations
-
Annotations as methods apply to any method
Note:
If a Profile class uses the Profile tag or the @profile function in any class must be enabled to take effect, if @profile ({“p1″,”! P2 “}) identifies two properties, so p1 is enabled and p2 is not enabled.
@ ImportResource and @ Configuration
@ImportResource: This annotation provides similar to @ Import functions, usually used with @ the Configuration, start by AnnotationConfigApplicationContext, here with a sample look at specific usage:
- Create a new TestService class under config and declare a constructor that will be called when the class is initialized
public class TestService {
public TestService(a){
System.out.println("test @importResource success"); }}Copy the code
- Create importResources.xml in the /resources directory to import TestService
<?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"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="Http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd"
>
<bean id = "testService" class="com.spring.configuration.config.TestService" />
</beans>
Copy the code
- Then a new ImportResourceWithConfiguration under config, used for reading configuration files
@Configuration
@ImportResource("classpath:importResources.xml")
public class ImportResourceWithConfiguration {
@Autowired
private TestService service;
public void getImportResource(a){
new TestService();
}
public static void main(String[] args) {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(ImportResourceWithConfiguration.class);
context.getBean("testService"); }}Copy the code
Output: test@importResource success
@ Configuration nesting
The @Configuration annotation applies to classes, just like normal classes, to each other and define inner classes.
/ / from the JavaDoc
@Configuration
public class AppConfig{
@Inject
DataSource dataSource;
@Bean
public MyBean myBean(a){
return new MyBean(dataSource);
}
@Configuration
static class DataConfig(a){
@Bean
DataSource dataSource(a){
return new EmbeddedDatabaseBuilder().build()
}
}
}
Copy the code
In the above code, you just need to register AppConfig in the context of your application. Since it is a nested @Configuration class, DatabaseConfig will be automatically registered. This obviates the need for @import annotations when the relationship between AppConfig and DatabaseConfig is already implicit.
@lazy Lazy initialization
Lazy: indicates whether a bean is lazily loaded, which can be applied to a method to indicate that the method is lazily loaded. Can be applied to classes annotated with @Component (or with @Component as the original annotation) to indicate that all beans in the class are lazily loaded. If there is no @lazy annotation, or if @lazy is set to false, then the bean is eager to be loaded; In addition to the two scopes above, @lazy can also be applied to @Autowired and @Inject annotated properties, in which case it will create an inert proxy for that field as the default method to use ObjectFactory or Provider. Here’s a demonstration:
- Modify the
MyConfiguration
Class, add an @lazy annotation to the class, add an IfLazyInit() method, and check that it is initialized.
@Lazy
@Configuration
@ComponentScan(basePackages = "com.spring.configuration.pojo")
public class MyConfiguration {
@Bean
public MyBean myBean(a){
System.out.println("myBean Initialized");
return new MyBean();
}
@Bean
public MyBean IfLazyInit(a){
System.out.println("initialized");
return newMyBean(); }}Copy the code
- Modify SpringConfigurationApplication start class, let go of MyConfiguration before start the class
public class SpringConfigurationApplication {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyConfiguration.class);
// ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
// AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
// context.register(MyConfiguration.class);
// context.refresh();
//
// // gets the name of the bean definition during startup
for(String str : context.getBeanDefinitionNames()){
System.out.println("str = " + str);
}
// context.close();
// ApplicationContext context =
// new AnnotationConfigApplicationContext(ReadValueFromPropertySource.class);
// MyBean myBean = (MyBean) context.getBean("myTestBean");
// System.out.println("myBean = " + myBean);}}Copy the code
You will find no definition information about the bean, but when you remove the @lazy annotation, you will find initialization information about the bean:
myBean Initialized generate MyBean Instance initialized generate MyBean Instance
@ RunWith and @ ContextConfiguration
Junit4 test class, used to annotate a class to indicate that it is being tested by Junit4. You can omit the starting class code and is an alternative to starting classes such as ApplicationContext. Unit testing with @runWith and @Configuration is a necessary and professional part of the software development process, as evidenced by the EnvironmentConfig class above:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = EnvironmentConfig.class)
@Configuration
@PropertySource("classpath:beanName.properties")
public class EnvironmentConfig {
// @Autowired
// Environment env;
@Inject
Environment env;
@Test
public void testReadProperty(a){
// Get the bean.name.controller property
System.out.println(env.getProperty("bean.name.controller"));
// Check whether bean.name.component is included
System.out.println(env.containsProperty("bean.name.component"));
// Returns the value of the attribute associated with the given key
System.out.println(env.getRequiredProperty("bean.name.service")); }}Copy the code
@enable Enables Spring’s built-in features
Details refer to @ EnableAsync, @ EnableScheduling, @ EnableTransactionManagement, @ EnableAspectJAutoProxy, @ EnableWebMvc official documentation
@configuration Indicates the usage restriction
- Must be supplied as a class (that is, not an instance returned from a factory method)
- Classes annotated by @Configuration must be non-final
- Configuration classes must be non-native (that is, may not be declared in methods),native annotated methods
- Any nested @Configuration must be static.
- The @bean method may not in turn create more configuration classes
References:
Docs. Spring. IO/spring – fram…
Docs. Spring. IO/spring – fram…
Blog.csdn.net/u012734441/…