Notes on Spring annotation development

Notes and their functions:

@Configuration: configuration annotation, which is modified on the configuration class. It tells Spring that this is a configuration class, and the configuration class is equivalent to the configuration file.

@ComponentScan: component scanning annotation, decorated on the configuration class, specifies the package to be scanned when the container starts, and lists the class marked by the annotation specified below the package into the container.

@Bean: when a method is used to create an object, the method parameters are directly obtained from the container. Parameters can be marked @ Autowired.

@Import

@Lazy: used in singleton mode

@PostConstruct: the method called after the marker object is created and assigned a value (used on the method)

@PreDestroy: marks the method called before the container removes the object (used on the method)

 

 

 

 

@Conditional (conditional class): if it is placed on the method, judge according to certain conditions, and register the bean object to the container if the conditions are met; If it is placed on a class, it means that this condition is met, and all bean registrations in this class will take effect. A judgment condition class needs to be set. Examples are as follows:

First, create a condition class, which needs to implement org springframework. context. annotation. Condition interface:

package jx.condition;

import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotatedTypeMetadata;

public class MacCondition implements Condition {

    /**
     * @param conditionContext Determine the context (environment) that the condition can use
     * @param annotatedTypeMetadata Annotation information
     * @return Is the return condition true
     */
    @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
        Environment environment = conditionContext.getEnvironment();
        String property = environment.getProperty("os.name");
        if (property.contains("Mac")){
            return true;
        }else {
            return false;
        }
    }
}

Call example:

package jx.config;

import jx.bean.Person;
import jx.condition.MacCondition;
import jx.condition.WindowsCondition;
import org.springframework.context.annotation.*;

@Configuration //Tell Spring that this is a configuration class, which is equivalent to a configuration file.
@Conditional(WindowsCondition.class)//If it is placed on a class, it means that this condition is met, and all bean registrations in this class will take effect
public class MainConfig2 {

    //If it is placed on the method, judge according to certain conditions, and register the bean object to the container if the conditions are met
    @Conditional(WindowsCondition.class)
    @Bean("win")
    public Person person1(){
        return new Person("win", 100);
    }

    @Conditional(MacCondition.class)
    @Bean("ios")
    public Person person2(){
        return new Person("ios",120);
    }

}

 

 

 

 

To register components in a container:

1. Package scanning + Component annotation (@ Controller/@Service/@Repository/@Component)

Specify the package to be scanned when the container starts by adding the component scanning annotation @ ComponentScan(value = "package name") on the configuration class, where value specifies the package name to be scanned. All classes marked by @ Controller/@Service/@Repository/@Component and other annotations under this package will be registered in the container.

package jx.config;

import jx.bean.Person;
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.Controller;
import org.springframework.stereotype.Service;

//A configuration class is equivalent to a configuration file
@Configuration //Tell Spring that this is a configuration class
@ComponentScan(value = "jx")//value: specify the package to scan;
public class MainConfig {
    //Register a bean for the container; The type is the type of return value, and the default method is the id.
    @Bean("person")//The value attribute is used to record the id. the default mode is singleton mode.
    public Person person(){
        return new Person("lisi",25);
    }
}

The component scanning annotation has the following attributes:

excludeFilters = Filter []: which components are excluded according to the specified rules during scanning.

@ComponentScan(value = "jx", excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class, Service.class})})

includeFilters = Filter []: which components only need to be included during scanning, and useDefaultFilters=false must be used at the same time;

@ComponentScan(value = "jx", includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class})}, useDefaultFilters = false)

FilterType.ASSIGNABLE_TYPE: filter according to the given type

FilterType.ASPECTJ: filter according to ASPECTJ expression

FilterType.REGEX: filter by REGEX expression

FilterType.CUSTOM: filter according to user-defined rules. Examples are as follows:

First, you need to create a filtering class to indicate the filtering rules. This class needs to implement the TypeFilter interface:

package jx.config;

import org.springframework.core.io.Resource;
import org.springframework.core.type.AnnotatedTypeMetadata;
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;

//Customize a filter rule
public class MyTypeFilter implements TypeFilter {
    @Override
    public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
        //Gets the annotation information of the current class
        AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
        //Gets the class information of the class currently being scanned
        ClassMetadata classMetadata = metadataReader.getClassMetadata();
        //Get the current class resource (the path of the class)
        Resource resource = metadataReader.getResource();
        String className = classMetadata.getClassName();
        if (className.contains("er")){
            return true;
        }
        //System.out.println("---->" + className);
        return false;
    }
}

Then specify the use of filtertype in the attribute of @ ComponentScan Custom: filter according to user-defined rules. The specific code is as follows:

@ComponentScan(value = "jx", includeFilters = {@ComponentScan.Filter(type = FilterType.CUSTOM, classes = {MyTypeFilter.class})}, useDefaultFilters = false)

2. @ Bean [components in imported third-party packages]

    @Bean("person")//The value attribute is used to record the id,
    public Person person(){
        System.out.println("objects creating");
        return new Person("lisi",25);
    }

3. @ Import [quickly Import a component into the container]

(1) @ import (component to be imported into the container): this component will be automatically registered in the container, and the id is the full class name of the component by default;

Add the following code to the configuration class: you can add a class to Import, or use the middle extension to add an array of multiple classes.

@Configuration //Tell Spring that this is a configuration class
@Import({Color.class})//Quickly import components. The default id is the full class name of the component
public class MainConfig2 {

(2) ImportSelector: returns the full class name array of the component to be imported; (it is commonly used and needs to be mastered)

To define an ImportSelector class, you need to implement the ImportSelector interface:

package jx.condition;

import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;

public class MyImportSelector implements ImportSelector {

    @Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        return new String[]{"jx.bean.Blue"};//Note that the full path name of the class is written here
    }
}

Add the following parameters to Import:

@Configuration //Tell Spring that this is a configuration class
@Import({Color.class, MyImportSelector.class})//Quickly import components. The default id is the full class name of the component
public class MainConfig2 {}

(3) improvbeandefinitionregistrar: manually register beans into the container.

(4) use the factory bean interface provided by Spring. (it is commonly used and needs to be mastered)

To define a factory bean, you need to implement the FactoryBean interface:

package jx.bean;

import org.springframework.beans.factory.FactoryBean;

public class ColorFactoryBean implements FactoryBean {

    @Override
    public Object getObject() throws Exception {
        return new Color();
    }

    @Override
    public Class<?> getObjectType() {
        return Color.class;
    }

    //Configure whether this class is in singleton mode
    @Override
    public boolean isSingleton() {
        return true;
    }
}

Add the created factory bean to the configuration class:

    @Bean
    public ColorFactoryBean colorFactoryBean(){
        return new ColorFactoryBean();
    }

Test: note that the output here is the type described in the factory class, not the factory type!!!

be careful:

(1) By default, the object created by the factory bean calling getObject is obtained

(2) If you want to get the factory bean itself, you need to prefix the id with a & symbol, such as & colorfactorybean

    @Test
    public void test4(){
        Object bean = applicationContext.getBean("colorFactoryBean");
        System.out.println(bean.getClass());//The output here is the type described in the factory class, not the factory type
    }

 

Notes related to life cycle:

bean life cycle: create --- initialize --- destroy

Lifecycle of container managed bean s: initialization and destruction methods can be customized.

Object creation:

Single example: create an object when the container starts.

Multiple examples: create an object every time you get an object.

Object initialization: after object creation and assignment are completed, the initialization method is called.

Object destruction:

Single example: destroy when container is closed

Multiple examples: the container will not manage this bean, that is, after the container is closed, the container will not call the destruction method.

(1) By setting initMethod = "initialization method name defined in class" and destroyMethod = "destruction method name defined in class" in @ Bean

Define initialization and destruction methods in the class:

package jx.bean;

public class Car {

    public Car(){
        System.out.println("Car---establish");
    }

    public void init(){
        System.out.println("Car---initialization");
    }

    public void destroy(){
        System.out.println("Car---Destroy");
    }
}

Then specify in the @ Bean annotation attribute on the method of creating this class in the configuration class:

    @Bean(initMethod = "init", destroyMethod = "destroy")
    public Car car(){
        return new Car();
    }

(2) By letting the bean implement the InitializingBean (defining initialization logic) and DisposableBean (defining destruction logic) interfaces.

package jx.bean;

import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;

@Component
public class Car implements InitializingBean, DisposableBean {

    public Car(){
        System.out.println("Car---establish");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("Car---initialization");
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("Car---Destroy");
    }
}

(3) use the @ PostConstruct annotation in JSR250 to execute the initialization method after the bean creation and assignment are completed@ PreDestroy annotation that notifies the container to clean up before destroying beans.

package jx.bean;

import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

@Component
public class Dog {

    public Dog() {
        System.out.println("Dog---Constructor---");
    }

    @PostConstruct//Called after object creation and assignment
    public void init(){
        System.out.println("Dog----init----");
    }

    @PreDestroy//Called before the container removes an object
    public void destroy(){
        System.out.println("Dog----destroy---");
    }
}

(4) BeanPostProcessor, post processor of bean: postProcessBeforeInitialization(Object bean, String beanName) -- work before initialization; The postProcessAfterInitialization(Object bean, String beanName) method works after initialization. This interface is widely used in the underlying principles of Spring.

package jx.bean;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;

//The post processor performs processing before and after initialization
@Component//Add the post processor to the container
public class MyBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessBeforeInitialization---"+ beanName);
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessAfterInitialization---"+ beanName);
        return bean;
    }
}

 

 

Comments related to attribute assignment:

@Value:

1. Basic type

2. SpEL type: #{}

3. ${}: take out the value in the configuration file (properties file) (value in environment variable)

The specific application methods are as follows:

    @Value("king")
    private String name;
    @Value("#{28-2}")
    private Integer age;
    @Value("${person.nikeName}")
    private String nikeName;

On the configuration class, use @ PropertySource to read the key/value in the external configuration file and save it to the running environment variable:

@PropertySource("classpath:/person.properties")
@Configuration
public class MainConfigOfPropertyValues {
    @Bean
    public Person person(){
        return new Person();
    }
}

 

Automatic assembly:

(1) @Autowired --- auto injection

1) the default priority is to find the corresponding component in the container according to the type: ApplicationContext getBean(PersonDao.class)

2) if multiple components of the same type are found, take the name of the attribute as the id of the component and look it up in the container: ApplicationContext getBean(“personDao”)

3) @ Qualifier("personDao"): use @ Qualifie to specify the id of the component to be assembled instead of the attribute name

4) by default, the attribute must be assigned well for automatic assembly, and an error will be reported if there is no one, but @ Autowired(required=false) can be used to specify that the component is not necessary.

5) @ Primary, when Spring performs automatic assembly, the preferred bean is used by default. You can also continue to use @ Qualifier to specify the name of the bean to be assembled.

package jx.service;

import jx.dao.BookDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

@Service
public class BookService {

    @Qualifier("bookDao")
    @Autowired(required = false)
    public BookDao bookDao;

    public void print(){
        System.out.println(bookDao);
    }
}

(2) Spring also supports the use of @ Resource(JSR250) and @ Inject(JSR330) [both are java specification annotations]

@Resource: it can realize automatic assembly like @ Autowired; By default, it is assembled according to the component name. There is no function that supports @ Primary or @ Autowired(required = false)

@Inject: need to import javax The package of inject has the same function as @ Autowired

(3) @ Autowired can be marked on constructors, methods, parameters and attributes, all of which obtain the value of component parameters from the container.

(a) marked on the method:

(b) Mark on the constructor: if the component has only one constructor with parameters, @ Autowired of the constructor with parameters can be omitted

(c) Mark on parameters:

(4) The custom component wants to use some components (ApplicationContext,BeanFactory,xxx) at the bottom of the Spring container. The custom component implements the XXXAware interface. When creating an object, it will call the methods specified in the interface to inject relevant components; Aware imports some Spring underlying components into custom beans.

 

@Profile: Specifies the environment in which the component can be registered in the container. If it is not specified, the component can be registered in any environment.

(1) Beans with environment ID can be registered in the container only when the environment is activated. The default is the default environment.

(2) Written on the configuration class, all configurations in the entire configuration class can take effect only when the specified environment.

(3) Beans without environment ID are loaded in any environment.

There are two ways to change the environment:

(1) Use command line dynamic parameters: - dspring profiles. Active = Test (or other desired test environment)

(2) Activate an environment by code:

        //Create container with parameterless constructor
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        //Set the environment that needs to be activated
        applicationContext.getEnvironment().setActiveProfiles("test","dev");
        //Register master configuration class
        applicationContext.register(MainConfigOfProfile.class);
        //Start refresh container
        applicationContext.refresh();

    

AOP: refers to the method of dynamically cutting in a piece of code during the running of a program.

 

1. In POM Import aop module into XML: Spring AOP (spring aspects)

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>5.2.4.RELEASE</version>
        </dependency>

2. Define a business logic class: print the log when the business logic is running

package jx.aop;

public class MathCalculator {

    public int div(int i, int j){
        System.out.println("Method run...");
        return i/j;
    }
}

3. Define a log facet class: the methods in the facet class need to dynamically perceive the operation of business methods

Notification method: pre notification (@ Before): run Before the target method runs

Post notification (@ After): run After the target method runs

Return notification (@ AfterReturning): run after the target method returns normally

Exception notification (@ AfterThrowing): run after an exception occurs in the target method

Surround notification (@ Around): dynamic proxy, manually advancing the target method (joinPoint.procced())

4. Mark when and where to run the target method of the aspect class (notify annotation);

package jx.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;

import java.util.Arrays;

@Aspect
public class LogAspects {

    @Before("execution(public int jx.aop.MathCalculator.*(..))")
    public void logStrat(JoinPoint joinPoint){
        Object[] args = joinPoint.getArgs();
        System.out.println(joinPoint.getSignature().getName()+"Method runs. The parameter list is:"+ Arrays.asList(args).toString()+"+}. ");
    }

    @After("execution(public int jx.aop.MathCalculator.*(..))")
    public void logEnd(){
        System.out.println("End of method run......");
    }

    @AfterReturning(value = "execution(public int jx.aop.MathCalculator.*(..))",returning = "result")
    public void logReturn(Object result){
        System.out.println("After the method runs, the returned result is:"+result+"");
    }

    @AfterThrowing(value = "execution(public int jx.aop.MathCalculator.*(..))", throwing = "exception")
    public void logException(Object exception){
        System.out.println("Exception occurred in method...."+exception.toString());
    }
}

5. Both facet classes and business logic classes are added to the container

package jx.config;

import jx.aop.LogAspects;
import jx.aop.MathCalculator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@EnableAspectJAutoProxy
@Configuration
public class MainConfigOfAOP {

    //Add business logic classes to the container
    @Bean
    public MathCalculator mathCalculator(){
        return new MathCalculator();
    }

    //Add the cut class to the container
    @Bean
    public LogAspects logAspects(){
        return new LogAspects();
    }
}

6. Tell Spring which Aspect class is (@ Aspect)

@Aspect
public class LogAspects {

7. Add @ EnableAspectJAutoProxy to the configuration class (enable annotation based aop mode)

@EnableAspectJAutoProxy
@Configuration
public class MainConfigOfAOP {

Summarize the steps to create aop:

(1) Add both business logic components and Aspect classes to the container: Tell Spring which is the Aspect class (@ Aspect)

(2) Mark the notification annotation on each notification method on the aspect class to tell Spring when and where to run (pointcut expression)

(3) Enable annotation based aop mode: @ EnableAspectJAutoProxy

 

AOP principle summary:

(1) @ EnableAspectJAutoProxy enable AOP function;

(2) @ EnableAspectJAutoProxy will register a component annotation awareaspectjautoproxycreator in the container;

(3) Annotation awareaspectjauto proxycreator is a post processor;

(4) Container creation process:

1) registerBeanPostProcessors() registers the post processor and creates the AnnotationAwareAspectJAutoProxyCreator object;

2) finishBeanFactoryInitialization() initializes the remaining single instance beans

a. Create business logic components and aspect components

b. AnnotationAwareAspectJAutoProxyCreator intercepts the creation process of the component

c. After the component is created, judge whether the component needs to be enhanced. If so, the aspect notification method is packaged into an enhancer (Advisor); Create a proxy object for the business logic component.

(5) Implementation target method:

1) The proxy object executes the target method;

2)CglibAopProxy.intercept();

a. Obtain the interceptor chain of the target method (the intensifier is packaged as interceptor MethodInterceptor)

b. Use the chain mechanism of interceptors to enter each interceptor in turn for execution;

c. Effect:

Normal execution: pre Notification - target method - post Notification - return notification

Exception occurred: pre Notification - target method - post Notification - exception notification

 

Declarative transaction:

Environment construction:

1. In POM Import relevant dependencies in XML file: data source, database driver and spring JDBC module

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.2.4.RELEASE</version>
        </dependency>

2. Configure the data source and operation data of JdbcTemplate (a tool provided by Spring to simplify database operation) in the configuration class, and register them in the container.

    //data source
    @Bean
    public DataSource dataSource() throws Exception {
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        dataSource.setUser(user);
        dataSource.setPassword(pwd);
        dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test");
        dataSource.setDriverClass(driverClass);
        return dataSource;
    }

    @Bean
    public JdbcTemplate jdbcTemplate() throws Exception{
        //Spring will carry out special treatment on @ Configuration class, adding component methods to the container. Multiple calls are only to find components from the container
        JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource());
        return jdbcTemplate;
    }

3. Mark @ Transactional on the method to indicate that the current method is a transaction method.

    @Transactional
    public void insertUser(){
        userDao.insert();
        System.out.println("Insertion complete!");
    }

4. Configure the transaction manager to manage the transaction platform transaction manager and register it in the container.

    //Register the transaction manager in the container
    @Bean
    public PlatformTransactionManager platformTransactionManager() throws Exception{
        return new DataSourceTransactionManager(dataSource());
    }

5. Mark @ EnableTransactionManagement on the configuration class to enable the annotation based transaction management function.

@EnableTransactionManagement//Enable annotation based transaction management
@PropertySource("classpath:/dbconfig.properties")
@ComponentScan
@Configuration
public class TxConfig {

Declarative transaction principle:

(1)@EnableTransactionManagement

Autoproxyregister and ProxyTransactionManagementConfiguration will be imported into the container by using TransactionManagementConfigurationSelector

(2) Autoproxyregister: register an infrastructure advisor autoproxycreator component in the container. The component uses the post processor mechanism to wrap the object and return a proxy object (enhancer) after the object is created. The proxy object execution method uses the interceptor chain to intercept

(3)ProxyTransactionManagementConfiguration:

1) To register a transaction enhancer in a container:

a) The transaction enhancer uses the information of the transaction annotation, and the annotation transaction attributesource parses the event

b) Transaction Interceptor: transaction Interceptor: it saves the transaction attribute information. The transaction manager is a MethodInterceptor that executes the interceptor chain when the target method is executed. The execution process is as follows: 1. Obtain the transaction related attributes first; 2. If no TransactionManager is added and specified in advance, a platform TransactionManager will be obtained from the container according to the type; 3. Execute the target method. If it is abnormal, get the transaction manager and use the transaction management rollback operation; If normal, use the food manager to commit the transaction.

 

Expansion principle:

 

Event listener

@EventListener(classes = {ApplicationEvent.class}): event listening annotation. The classes attribute indicates which events to listen to

    @EventListener(classes = {ApplicationEvent.class})
    public void listen(){
        System.out.println("UserService====Listening events====");
    }

 

Tags: Spring annotations

Posted by Shawazi on Sat, 07 May 2022 01:07:17 +0300