Continue to summarize and update…

The Spring IOC container

Importing IOC dependencies

<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> < version > 4.3.12. RELEASE < / version > < / dependency >Copy the code

How to register components with a container

Package scan + Component annotation (@controller / @service / @repository /@Component)

Add @ComponentScan annotations to Configuration classes (classes annotated with @Configuration annotations). This method is limited to classes implemented by yourself. Third party classes cannot modify the source code and cannot add annotations to classes.

@configuration // tells Spring this is a Configuration class @ComponentScan(value="com.xxx") public class MainConfig {} @Controller public class BookController { } @Test public void test01(){ AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class); String[] definitionNames = applicationContext.getBeanDefinitionNames(); for (String name : definitionNames) { System.out.println(name); }}Copy the code

Using @Configuration indicates a Configuration class. The configuration bean package is scanned using @ComponentScan, which has several properties

  • Value: specifies the packets to be scanned.
  • ExcludeFilters = Filter[] : excludeFilters include the @filter array that specifies which components to exclude when scanning;
  • IncludeFilters = Filter[] : includeFilters include the @filter array that specifies which components to include when scanning;
    • @ Filter annotations
      • Filtertype. ANNOTATION: Follow the ANNOTATION
      • Filtertype. ASSIGNABLE_TYPE: according to the given type;
      • Filtertype. ASPECTJ: Uses ASPECTJ expressions
      • Filtertype. REGEX: specifies with the re
      • FilterType. CUSTOM: To use custom rules, you need to write a rule class that implements the TypeFilter interface, override the match(MetadataReaderFactory MetadataReaderFactory) method, Method returns true to indicate a match.

The includeFilters property requires the useDefaultFilters = false attribute to disable default filters. You can specify multiple @ComponentScan rules using @ComponentScans.

Integrated case

@ComponentScans(value= {@ComponentScan(value="com.atguigu",includeFilters = {@componentScan (value="com.atguigu"); //@Filter(type=FilterType.ANNOTATION,classes={Controller.class}), //@Filter(type=FilterType.ASSIGNABLE_TYPE,classes={BookService.class}), @Filter(type=FilterType.CUSTOM,classes={MyTypeFilter.class}) },useDefaultFilters = false) }) public class MainConfig { // Register a Bean in the container; @bean ("person") public person Person01 (){return new person ("lisi", 20); }} public class MyTypeFilter implements TypeFilter {/** * metadataReader: */ @override public Boolean match(MetadataReader MetadataReader) MetadataReader MetadataReaderFactory MetadataReaderFactory) throws IOException {// TODO auto-generated method stub // Obtains information about the current class annotation AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata(); / / get the current classes is scanning the information ClassMetadata ClassMetadata = metadataReader. GetClassMetadata (); / / get the current Resource (path) Resource Resource. = metadataReader getResource (); String className = classMetadata.getClassName(); System.out.println("--->"+className); If (classname. contains("er")){return true; } return false; }}Copy the code

Declare [components in imported third-party packages] with the @bean annotation

Public class MainConfig {// Register a Bean in the container; Type is the type of the return value, id defaults to the method name as id, @bean ("person") public person Person01 (){return new person ("lisi", 20); }}Copy the code
@ Test public void test01 () {/ / using AnnotationConfigApplicationContext loading configuration class ApplicationContext ApplicationContext = new AnnotationConfigApplicationContext(MainConfig.class); Person bean = applicationContext.getBean(Person.class); System.out.println(bean); }Copy the code

Use @import annotations

  • @import (components to be imported into containers); The component is automatically registered in the container, and the id defaults to the full class name; Use the @import annotation to add a class to the Spring container, such as the one below that adds Color to the Spring container.
@Configuration  
@Import({Color.class})
public class MainConfig {
}

public class Color {
}
Copy the code
  • ImportSelector: Imports a selector that returns an array of the full class names of the components to be imported;
@configuration@import ({MyImportSelector. Class}) public class MainConfig {} // Custom logic returns the public class of the component to be imported MyImportSelector implements ImportSelector {// Return value, AnnotationMetadata: @override public String[] selectImports(AnnotationMetadata) ImportingClassMetadata) {// TODO auto-generated method stub //importingClassMetadata // Method do not return null value return new String[]{"com.xxx.bean.Blue","com.xxx.bean.Yellow"}; } } public class Blue {} public class Yellow {}Copy the code
  • ImportBeanDefinitionRegistrar: manually register beans into the container
@Configuration @Import({MyImportBeanDefinitionRegistrar.class}) public class MainConfig { } public class AnnotationMetadata MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {/ * * * : The current class of annotation information * BeanDefinitionRegistry: BeanDefinition registered classes; * Add all beans that need to be added to the container; Call * BeanDefinitionRegistry registerBeanDefinition manual registration in * / @ Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, Boolean BeanDefinitionRegistry registry) {/ / their own logic definition = registry. ContainsBeanDefinition (" com. XXX. Beans. Red "); boolean definition2 = registry.containsBeanDefinition("com.xxx.bean.Blue"); If (definition && Definition2){// Specify Bean definition information; (Type of Bean, Bean...) RootBeanDefinition beanDefinition = new RootBeanDefinition(RainBow.class); / / register a Bean, Bean name specified registry. RegisterBeanDefinition (" rainBow ", beanDefinition); } } } public class Blue {} public class Yellow {}Copy the code

Using FactoryBeans provided by Spring

A FactoryBean is a factory, an interface into which the container calls getObject() to return an object.

// Declare a ColorFactoryBean. The actual bean type is Color. @Bean public ColorFactoryBean colorFactoryBean(){ return new ColorFactoryBean(); } public class ColorFactoryBean implements FactoryBean<Color> { @Override public Color getObject() throws Exception {// TODO auto-generated method stub System.out.println("ColorFactoryBean... getObject..." ); return new Color(); } // The Bean returns the type @override public Class<? > getObjectType() { // TODO Auto-generated method stub return Color.class; } // is it a singleton? //true: this bean is a single instance, save a copy in the container //false: multiple instances, each fetch will create a new bean; @Override public boolean isSingleton() { // TODO Auto-generated method stub return true; } @test public void testImport(){// The factory Bean gets the Object bean2 = created by calling getObject applicationContext.getBean("colorFactoryBean"); Object bean3 = applicationContext.getBean("colorFactoryBean"); System.out.println("bean type: "+bean2.getClass()); Color system.out. println(bean2 == bean3); // Returns true, indicating singleton. Because the isSingleton method of ColorFactoryBean returns true for a single instance, if it returns false, then bean2 is not bean3. / / by & get the factory Bean itself Object bean4 = applicationContext. GetBean (" & colorFactoryBean "); System.out.println(bean4.getClass()); // Return colorFactoryBean}Copy the code

To get the FactoryBean itself, we need to prefix the id with an &. That is, &colorfactorybean;

Use @scope to specify different scoped beans

By default, beans generated by the Spring container are singleton, and you can specify different scopes using @scope. In the @Scope source code, you can see the following Javadoc on the scopeName property.

/**
	 * Specifies the name of the scope to use for the annotated component/bean.
	 * <p>Defaults to an empty string ({@code ""}) which implies
	 * {@link ConfigurableBeanFactory#SCOPE_SINGLETON SCOPE_SINGLETON}.
	 * @since 4.2
	 * @see ConfigurableBeanFactory#SCOPE_PROTOTYPE
	 * @see ConfigurableBeanFactory#SCOPE_SINGLETON
	 * @see org.springframework.web.context.WebApplicationContext#SCOPE_REQUEST
	 * @see org.springframework.web.context.WebApplicationContext#SCOPE_SESSION
	 * @see #value
	 */
Copy the code

ConfigurableBeanFactory specifies a Scope’s Scope: SCOPE_SINGLETON and SCOPE_PROTOTYPE. Using the WebApplicationContext, you can specify SCOPE_REQUEST (creating an instance of the same request in the Web environment) and SCOPE_SESSION (creating an instance of the same Session in the Web environment).

@scope ("prototype") @bean ("person") public person(){system.out.println (" add person.... to container ") ); Return new Person(" Person ", 25); }Copy the code

Note:

Prototype: multi-instance: ioc container startup doesn’t call methods to create objects in the container, it only calls methods to create objects on each fetch; Singleton: Singleton (default) : The ioc container starts by calling methods to create objects and place them in the IOC container, then fetching them directly from the container (map.get()).

Use @lazy to load the Bean

Beans in Spring are singleton by default, creating objects when the container is started by default; Lazy-loaded beans can then be implemented using @lazy, where the container starts without creating objects. The first time an object is created and initialized using a (get)Bean;

@lazy @bean ("person") public person person(){system.out.println (" Add person.... to container ") ); Return new Person(" Person ", 25); }Copy the code

Use @Conditional to register beans to the container for conditions

@Conditional({Condition}) : The bean registered in the container can be judged according to certain conditions

@Conditional annotations can be added to methods or classes.

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {

/**
 * All {@link Condition}s that must {@linkplain Condition#matches match}
 * in order for the component to be registered.
 */
Class<? extends Condition>[] value();

}
Copy the code

The @Conditional annotation value attribute requires a class that implements the Condition annotation, overriding the matches method, which returns true for a match or false for a mismatch.

public interface Condition {

    /**
     * Determine if the condition matches.
     * @param context the condition context
     * @param metadata metadata of the {@link org.springframework.core.type.AnnotationMetadata class}
     * or {@link org.springframework.core.type.MethodMetadata method} being checked.
     * @return {@code true} if the condition matches and the component can be registered
     * or {@code false} to veto registration.
     */
    boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);

}
Copy the code

Example: Register with the container (” Bill “) on Windows, register with the container (” Linus “) on Linux

@Configuration public class MainConfig { @Bean("bill") public Person person01(){ return new Person("Bill Gates",62); } @Conditional(LinuxCondition.class) @Bean("linus") public Person person02(){ return new Person("linus", 48); }} public class LinuxCondition implements Condition {/** * ConditionContext */ @override public Boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {/ / TODO Linux system / / 1, to get to the ioc use the beanfactory ConfigurableListableBeanFactory the beanfactory  = context.getBeanFactory(); ClassLoader = context.getClassLoader(); Environment = context.getenvironment (); BeanDefinitionRegistry = context.getregistry (); BeanDefinitionRegistry = context.getregistry (); String property = environment.getProperty("os.name"); / / can be judged in a container bean registration situation, also can give the container registered bean Boolean definition = registry. ContainsBeanDefinition (" person "); if(property.contains("linux")){ return true; } return false; Public class WindowsCondition implements Condition {@override public Boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { Environment environment = context.getEnvironment(); String property = environment.getProperty("os.name"); if(property.contains("Windows")){ return true; } return false; }}Copy the code

The life cycle of the Bean

The bean life cycle is the process of bean creation, initialization and destruction. The container manages the bean life cycle. We can customize initialization and destruction methods; The container calls our custom initialization and destruction methods at the end of the bean’s current life cycle.

Specify initialization and destruction methods:

  • 1. Specify init-method and destroy-method via @bean;
@Configuration public class MainConfigOfLifeCycle { @Bean(initMethod="init",destroyMethod="detory") public Car car(){ return new Car(); } } public class Car { public Car(){ System.out.println("car constructor..." ); } public void init(){ System.out.println("car ... init..." ); } public void detory(){ System.out.println("car ... detory..." ); }} @test public void test01(){ Container created will instantiate Bean AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class); System.out.println(" Container created... ); //applicationContext.getBean("car"); // Close the container applicationContext.close(); }Copy the code

/ / after the operation

car constructor… car … init… Container created… car … detory… So,

  • Construct (object creation) timing,
- Single-instance: objects are created when the container is started. - Multi-instance: objects are created each time the container is fetchedCopy the code
  • Initialization time: the object is created and assigned, and the initialization method is called…
  • Destruction time:
- Single-instance: when the container is closed - multi-instance: the container will not manage this bean; The container does not call the destruction method;Copy the code
  • 2. Make the Bean InitializingBean to DisposableBean by defining the initialization logic;
@ComponentScan("com.xxx.bean") @Configuration public class MainConfigOfLifeCycle { } @Component public class Cat implements InitializingBean,DisposableBean { public Cat(){ System.out.println("cat constructor..." ); } @Override public void destroy() throws Exception { // TODO Auto-generated method stub System.out.println("cat... destroy..." ); } @Override public void afterPropertiesSet() throws Exception { // TODO Auto-generated method stub System.out.println("cat... afterPropertiesSet..." ); }}Copy the code
  • 3. You can use the two annotations defined in the JSR250 specification;
    • PostConstruct: The bean is created and the property assignment is completed; To perform the initialization method.
    • PreDestroy: Notify us of the cleanup before the container destroys the bean.
@Component public class Dog implements ApplicationContextAware { //@Autowired private ApplicationContext applicationContext; public Dog(){ System.out.println("dog constructor..." ); } @postconstruct public void init(){system.out.println ("Dog...." @PostConstruct..." ); } @predestroy public void detory(){system.out.println ("Dog.... @PreDestroy..." ); } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { // TODO Auto-generated method stub this.applicationContext = applicationContext; }}Copy the code

Intercept beans before and after initialization using BeanPostProcessor

BeanPostProcessor interface: bean backend processor; Do some processing before and after bean initialization; PostProcessBeforeInitialization: before initialization work (such as InitializingBean. AfterPropertiesSet () before, Or custom init – performed before) postProcessAfterInitialization method method: after initialization work (such as InitializingBean. AfterPropertiesSet (), Or execute after custom init-method method.)

  • Usage:
/** * */ @component public class MyBeanPostProcessor implements BeanPostProcessor {@override implements BeanPostProcessor public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { System.out.println("postProcessBeforeInitialization..." +beanName+"=>"+bean); return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { System.out.println("postProcessAfterInitialization..." +beanName+"=>"+bean); return bean; }}Copy the code
  • Principle:

Tracking source to AbstractAutowireCapableBeanFactory initializeBean method of a class.

protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) { if (System.getSecurityManager() ! = null) { AccessController.doPrivileged(new PrivilegedAction<Object>() { @Override public Object run() { invokeAwareMethods(beanName, bean); return null; } }, getAccessControlContext()); } else { invokeAwareMethods(beanName, bean); } Object wrappedBean = bean; if (mbd == null || ! mbd.isSynthetic()) { wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); } try { invokeInitMethods(beanName, wrappedBean, mbd); } catch (Throwable ex) { throw new BeanCreationException( (mbd ! = null ? mbd.getResourceDescription() : null), beanName, "Invocation of init method failed", ex); } if (mbd == null || ! mbd.isSynthetic()) { wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); } return wrappedBean; }Copy the code

Collate cut above source code:

populateBean(beanName, mbd, instanceWrapper); InitializeBean {// Iterate over all beanPostProcessors in the container; Execute beforeInitialization one by one, // Once returns null, breaks the for loop, Don't perform the back of the BeanPostProcessor postProcessorsBeforeInitialization applyBeanPostProcessorsBeforeInitialization (wrappedBean, beanName); invokeInitMethods(beanName, wrappedBean, mbd); Perform custom initialization applyBeanPostProcessorsAfterInitialization (wrappedBean, beanName); }Copy the code

Initialization applyBeanPostProcessorsBeforeInitialization () method is performed before the operation; The invokeInitMethods() method performs the initialization; ApplyBeanPostProcessorsAfterInitialization () method performs initialization after operation. The entire initializeBean() method is executed after the populateBean() method, which assigns attributes to the bean.

Spring’s underlying use of BeanPostProcessor

There are three ways to assign a Value to an attribute using @value:

There are three ways to assign a Value to an attribute using @value:

  • The basic numerical
  • You could write SpEL; # {}
  • You can write ${}; Fetch the value in the configuration file properties (the value in the runtime environment variable)
// Use @propertysource to read k/ V from the external configuration file and save it to the running environment variable; After loading the external Configuration file using the ${} take out the value of the Configuration file @ PropertySource (value = {} "the classpath: / person. The properties") @ Configuration public class MainConfigOfPropertyValues { @Bean public Person person(){ return new Person(); }} public class Person {// use @value; //1; //2; ${}}; @value (" zhang 3 ") private String name; // SpEL @Value("#{20-2}") private Integer age; @value ("${person.nickname}") private String nickName; }Copy the code

Spring automatic assembly

Automatic assembly concept

Spring uses dependency injection (DI) to assign dependencies to components in the IOC container.

Automatic assembly mode

Use @autoWired for automatic injection

In common use, Autowired annotations are automatically injected on attributes
- the default priority according to the type to find the corresponding components in the container: applicationContext. GetBean (XXX. Class); Find on assignment; @service public class BookService {@autoWired private BookDao BookDao; public void print(){ System.out.println(bookDao); } @Override public String toString() { return "BookService [bookDao=" + bookDao + "]"; } @repository public class BookDao {} ' '  ``` @Test public void test01(){ AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConifgOfAutowired.class); BookService bookService = applicationContext.getBean(BookService.class); System.out.println(bookService); applicationContext.close(); } ` ` ` - if found multiple components of the same type, then the name of the attribute as a component of id to container, find the similar applicationContext. GetBean (" XXX "); Public class BookDao {private String lable = "1"; private String lable = "1"; public String getLable() { return lable; } public void setLable(String lable) { this.lable = lable; } @Override public String toString() { return "BookDao [lable=" + lable + "]"; @bean ("bookDao2") public BookDao BookDao() {BookDao BookDao = new BookDao(); bookDao.setLable("2"); return bookDao; } ' 'test:  ``` @Test public void test01(){ AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConifgOfAutowired.class); BookService bookService = applicationContext.getBean(BookService.class); System.out.println(bookService); applicationContext.close(); } "" output: the default output is a BookDao with label 1, because the BookDao type finds multiple components that are the same, and then uses the attribute name as the component ID to find the container, that is, use the BookDao to find the BookDao with label 1. - @qualifier (" XXX ") : use @qualifier to specify the ID of the component to be assembled instead of the attribute name. ``` @Service public class BookService { @Qualifier("bookDao2") @Autowired private BookDao bookDao; public void print(){ System.out.println(bookDao); } @Override public String toString() { return "BookService [bookDao=" + bookDao + "]"; }} bean@repository public class BookDao {private String lable = "1"; public String getLable() { return lable; } public void setLable(String lable) { this.lable = lable; } @Override public String toString() { return "BookDao [lable=" + lable + "]"; Public BookDao BookDao() {BookDao BookDao = new BookDao(); bookDao.setLable("2"); return bookDao; BookDao2 is injected using @qualifier to specify that bookDao2 is declared in the BookService. - Autowiring by default must assign the properties well, if there is no component in the container will report an error; You can use @autoWired (Required =false) to inject if the component is found or not; -@primary: When Spring is autonealed, the preferred bean is used by default (@qualifier is not available in this case); You can also continue to use @qualifier to specify the name of the bean to be assembled; @qualifier ("bookDao2") cannot be used to specify beans because @primary is the preferred Bean. @AutoWired Private BookDao BookDao is injected as specified by @Qualifier. public void print(){ System.out.println(bookDao); } @Override public String toString() { return "BookService [bookDao=" + bookDao + "]"; }} bean@repository public class BookDao {private String lable = "1"; public String getLable() { return lable; } public void setLable(String lable) { this.lable = lable; } @Override public String toString() { return "BookDao [lable=" + lable + "]"; }} // The second declaration Bean uses @primary to indicate that even if there are multiple beans of type BookDao, Bookdao2@primary @bean ("bookDao2") public BookDao BookDao() {BookDao BookDao = new BookDao(); bookDao.setLable("2"); return bookDao; } ` ` `Copy the code

Autowired other uses

@autoWired can be tagged on constructors, parameters, methods, attributes; Both get the value of the parameter component from the container

  • Annotation in method position: @bean + method parameter; Parameters are taken from the container; If you don’t say @Autowired by default, it’s the same thing; It’s all self-assembly.
@Component public class Boss { private Car car; public Car getCar() { return car; } // The Spring container creates the current object and calls the method to complete the assignment; @autoWired public void setCar(Car Car) {this. Car = Car; } @Override public String toString() { return "Boss [car=" + car + "]"; } } @Component public class Car { public Car(){ System.out.println("car constructor..." ); } public void init(){ System.out.println("car ... init..." ); } public void detory(){ System.out.println("car ... detory..." ); }}Copy the code
  • Tag constructor: If the component has only one parameter constructor, the @autowired of the parameter constructor can be omitted, and the component at the parameter position can still be automatically fetched from the container
@component public class Boss {private Car Car; Public Boss(Car Car){this. Car = Car; System.out.println("Boss... Parameter constructor "); } public Car getCar() { return car; } public void setCar(Car car) { this.car = car; } @Override public String toString() { return "Boss [car=" + car + "]"; } } @Component public class Car { public Car(){ System.out.println("car constructor..." ); } public void init(){ System.out.println("car ... init..." ); } public void detory(){ System.out.println("car ... detory..." ); }}Copy the code
  • Place in parameter position:
    Copy the code

// A component that is added to the ioc container by default. When the container is started, it calls the no-parameter constructor to create the object, and then performs initialization, assignment, etc

@Component public class Boss { private Car car; Public Boss(@autoWired Car){this. Car = Car; public Boss(@autowired Car){this. Car = Car; System.out.println("Boss... Parameter constructor "); } public Car getCar() { return car; Public void setCar(Car Car) {this. Car = Car; } @Override public String toString() { return "Boss [car=" + car + "]"; } } @Component public class Car { public Car(){ System.out.println("car constructor..." ); } public void init(){ System.out.println("car ... init..." ); } public void detory(){ System.out.println("car ... detory..." ); }}Copy the code

Spring also supports annotations using the @Resource(JSR250) and @Inject(JSR330) Java specifications;

- @resource: can implement autowiring function like @autoWired; The default is to assemble by component name; - @autowired (reqiured=false) is not supported ``` @Service public class BookService { @Resource private BookDao bookDao; public void print(){ System.out.println(bookDao); } @Override public String toString() { return "BookService [bookDao=" + bookDao + "]"; }} bean@repository public class BookDao {private String lable = "1"; public String getLable() { return lable; } public void setLable(String lable) { this.lable = lable; } @Override public String toString() { return "BookDao [lable=" + lable + "]"; Public BookDao BookDao() {BookDao BookDao = new BookDao(); bookDao.setLable("2"); return bookDao; @primary = 1; @primary = 1; @primary = 2; @primary = 1; - @inject: package to import javax. Inject, which has the same function as Autowired. There is no required=false functionality; ``` @Service public class BookService { @Inject private BookDao bookDao; public void print(){ System.out.println(bookDao); } @Override public String toString() { return "BookService [bookDao=" + bookDao + "]"; }} bean@repository public class BookDao {private String lable = "1"; public String getLable() { return lable; } public void setLable(String lable) { this.lable = lable; } @Override public String toString() { return "BookDao [lable=" + lable + "]"; Public BookDao BookDao() {BookDao BookDao = new BookDao(); bookDao.setLable("2"); return bookDao; } ' 'print bookDao (lable = 2) with @inject. @primary works like Autowired, but without required=false.Copy the code

To sum up, @autowired, @Inject, @Resource can all be automatically assembled, the difference is that @Autowired:Spring defined; @Resource and @Inject are Java specifications. In addition, @Resource cannot be assembled by component name and @primary is not supported. @inject is the same as @AutoWired. It supports @primary, but @inject does not have required=false; It is recommended to use @autowired for auto-assembly. Automatic injection effect can rely mainly on AutowiredAnnotationBeanPostProcessor this post processor to parse the complete automatic assembly feature;

Implementing xxxAware injects some of Spring’s underlying components into custom beans

Custom components want to use some of the underlying components of the Spring container (ApplicationContext, BeanFactory, XXX); Custom component implementation xxxAware; When an object is created, the method specified by the interface is invoked to inject related components. XxxAware implements the Aware interface;

/**
 * Marker superinterface indicating that a bean is eligible to be
 * notified by the Spring container of a particular framework object
 * through a callback-style method. Actual method signature is
 * determined by individual subinterfaces, but should typically
 * consist of just one void-returning method that accepts a single
 * argument.
 *
 * <p>Note that merely implementing {@link Aware} provides no default
 * functionality. Rather, processing must be done explicitly, for example
 * in a {@link org.springframework.beans.factory.config.BeanPostProcessor BeanPostProcessor}.
 * Refer to {@link org.springframework.context.support.ApplicationContextAwareProcessor}
 * and {@link org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory}
 * for examples of processing {@code *Aware} interface callbacks.
 *
 * @author Chris Beams
 * @since 3.1
 */
public interface Aware {
}
Copy the code

Case study:

@Component public class Red implements ApplicationContextAware,BeanNameAware,EmbeddedValueResolverAware { private ApplicationContext applicationContext; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { // TODO Auto-generated method stub system.out.println (" incoming IOC: "+applicationContext); this.applicationContext = applicationContext; } @override public void setBeanName(String name) {// TODO auto-generated method stub system.out.println (" "+name); } @Override public void setEmbeddedValueResolver(StringValueResolver resolver) { // TODO Auto-generated method stub String resolveStringValue = resolver. ResolveStringValue (" hello ${OS. The name} I am # 18} {20 * "); System.out.println(" parsed string: "+resolveStringValue); }}Copy the code

XxxAware: function using xxxProcessor; Using ApplicationContextAware as an example, once the Bean is created, if the Bean implements the ApplicationContextAware interface, So there will be a rear ApplicationContextAwareProcessor processor inject ApplicationContext come in.

/** * {@link org.springframework.beans.factory.config.BeanPostProcessor} * implementation that passes the ApplicationContext to beans that * implement the {@link EnvironmentAware}, {@link EmbeddedValueResolverAware}, * {@link ResourceLoaderAware}, {@link ApplicationEventPublisherAware}, * {@link MessageSourceAware} and/or {@link ApplicationContextAware} interfaces. * * <p>Implemented interfaces are satisfied in order of their mention above. * * <p>Application contexts will automatically register this with their * underlying bean factory. Applications do not use this directly. * * @author Juergen Hoeller * @author Costin Leau * @ the author Chris Beams * @ since 10.10.2003 * @ see org. Springframework. Context. EnvironmentAware * @ see org.springframework.context.EmbeddedValueResolverAware * @see org.springframework.context.ResourceLoaderAware * @see org.springframework.context.ApplicationEventPublisherAware * @see org.springframework.context.MessageSourceAware * @see org.springframework.context.ApplicationContextAware * @see org.springframework.context.support.AbstractApplicationContext#refresh() */ class ApplicationContextAwareProcessor implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException { AccessControlContext acc = null; if (System.getSecurityManager() ! = null && (bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware || bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware || bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)) { acc = this.applicationContext.getBeanFactory().getAccessControlContext(); } if (acc ! = null) { AccessController.doPrivileged(new PrivilegedAction<Object>() { @Override public Object run() { invokeAwareInterfaces(bean); return null; } }, acc); } else {// Inject invokeAwareInterfaces(bean) with this method; } return bean; } private void invokeAwareInterfaces(Object bean) { if (bean instanceof Aware) { if (bean instanceof EnvironmentAware) {  ((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment()); } if (bean instanceof EmbeddedValueResolverAware) { ((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver); } if (bean instanceof ResourceLoaderAware) { ((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext); } if (bean instanceof ApplicationEventPublisherAware) { ((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext); } if (bean instanceof MessageSourceAware) { ((MessageSourceAware) bean).setMessageSource(this.applicationContext); } if (bean instanceof ApplicationContextAware) { ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext); }}}}Copy the code

The source above you can see, is a rear ApplicationContextAwareProcessor processor, can be carried in the Bean initialization before postProcessBeforeInitialization method, And then determine whether the Bean implementation of Aware interface, the related Bean injected, can see ApplicationContextAwareProcessor can handle

org.springframework.context.EnvironmentAware
org.springframework.context.EmbeddedValueResolverAware
org.springframework.context.ResourceLoaderAware
org.springframework.context.ApplicationEventPublisherAware
org.springframework.context.MessageSourceAware
org.springframework.context.ApplicationContextAware
Copy the code

These Aware.

Create beans using @profile sub-environment

Profile: Spring provides us with the ability to dynamically activate and switch a series of components based on the current environment; @profile: Specifies the context in which a component can be registered in the container. If not specified, it can be registered in any context

  • A bean with an environment identifier can only be registered in the container if the environment is activated. The default is the default environment
  • 2), write on the configuration class, only when the specified environment, the entire configuration of the configuration class can take effect
  • 3) Beans without marked environment identifiers are loaded in any environment;

Take data source as an example, development environment, test environment, production environment; Use data sources :(/A)(/B)(/C);

/ / analytical dbconfig, respectively, using a variety of ways. The properties file @ PropertySource KV value (" classpath: / dbconfig. Properties ") @ Configuration public class MainConfigOfProfile implements EmbeddedValueResolverAware{ @Value("${db.user}") private String user; private StringValueResolver valueResolver; private String driverClass; @Bean public Yellow yellow(){ return new Yellow(); } @Profile("test") @Bean("testDataSource") public DataSource dataSourceTest(@Value("${db.password}")String pwd) throws Exception{ ComboPooledDataSource dataSource = new ComboPooledDataSource(); dataSource.setUser(user); dataSource.setPassword(pwd); dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test"); dataSource.setDriverClass(driverClass); return dataSource; } @Profile("dev") @Bean("devDataSource") public DataSource dataSourceDev(@Value("${db.password}")String pwd) throws Exception{ ComboPooledDataSource dataSource = new ComboPooledDataSource(); dataSource.setUser(user); dataSource.setPassword(pwd); dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/ssm_crud"); dataSource.setDriverClass(driverClass); return dataSource; } @Profile("prod") @Bean("prodDataSource") public DataSource dataSourceProd(@Value("${db.password}")String pwd) throws Exception{ ComboPooledDataSource dataSource = new ComboPooledDataSource(); dataSource.setUser(user); dataSource.setPassword(pwd); dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/scw_0515"); dataSource.setDriverClass(driverClass); return dataSource; } @Override public void setEmbeddedValueResolver(StringValueResolver resolver) { // TODO Auto-generated method stub this.valueResolver = resolver; driverClass = valueResolver.resolveStringValue("${db.driverClass}"); }}Copy the code

test

//1. Use command line dynamic parameters: load -dspring.profiles. active=test in the vm parameter position. @ Test public void test01 () {/ / use a no-parameter constructor to create AnnotationConfigApplicationContext AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(); / / 1, to create a applicationContext / / 2, set up the environment of the need to activate the applicationContext. GetEnvironment () setActiveProfiles (" dev "); / / 3, registered the master configuration applicationContext. Register (MainConfigOfProfile. Class); / / 4, initiate refresh applicationContext. Refresh (); String[] namesForType = applicationContext.getBeanNamesForType(DataSource.class); for (String string : namesForType) { System.out.println(string); } applicationContext.close(); }Copy the code

Spring AOP is faceted oriented programming

AOP concepts:

Refers to the programming method of dynamically cutting a piece of code into the specified location of the specified method to run during the operation of the program; The underlying principle uses dynamic proxy.

The basic use

1. AOP module (Spring AOP)

<dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> < version > 4.3.12. RELEASE < / version > < / dependency >Copy the code

2. Define a business logic class (MathCalculator)

Print the log while the business logic is running (before method, at the end of method, method exception, XXX)

public class MathCalculator { public int div(int i,int j){ System.out.println("MathCalculator... div..." ); return i/j; }}Copy the code

3. Define a log Aspect class

The methods in the section class need to dynamically know where mathCalculator.div is running and then execute;

Notification method

  • Pre-notification (@before) : Run Before the target method (div) runs, corresponding to LogAspects.logstart ()
  • Post-notification (@After) : Run After the target method (div) ends (whether the method ends normally or abnormally), corresponding to LogAspects.logend ()
  • Return notification (@AfterRETURNING) : runs after the target method (div) returns normally, corresponding to LogAspects.logreturn ();
  • Exception notification (@Afterthrowing) : run after an exception occurs in the target method (div), corresponding to LogAspects. LogException ();
  • Circular notification (@around) : Dynamic proxy that manually pushes the target method to run (joinPoint.procced())

Annotate when and where the target methods of the aspect class will run (various notification annotations, such as pre-notification, post-notification, etc.);

Spring must be told which class is the Aspect class (annotating the Aspect class with @aspect);

To sum up, the following code defines a section class:

@aspect // tells Spring that the current class is an Aspect class. Public Class LogAspects {// Extract common Pointcut expressions //1, class references //2, and other aspects references @pointcut ("execution(public) int com.atguigu.aop.MathCalculator.*(..) )") public void pointCut(){}; // @before Before the target method; @before ("pointCut()") public void logStart(JoinPoint JoinPoint){Object[] args = JoinPoint.getargs (); System.out.println(""+ JoinPoint.getSignature ().getName()+" Run... @before: The argument list is: {"+ arrays.asList (args)+"}"); } / / com. Atguigu. Aop. LogAspects. PointCut can use external classes () this way, LogAspects can define a tangent plane, external classes can be such a reference, Demonstrated here @ After (" com. Atguigu. Aop. LogAspects. PointCut () ") public void logEnd (JoinPoint JoinPoint) { Println (""+ JoinPoint.getSignature ().getName()+" End... @After"); } //JoinPoint must appear first in the parameter table, Return @afterreturning (value="pointCut()",returning="result") public void LogReturn (JoinPoint JoinPoint,Object result){system.out.println (""+ JoinPoint.getSignature ().getName()+" {"+result+"}"); @afterthrowing (value="pointCut()",throwing="exception") public void LogException (JoinPoint JoinPoint,Exception Exception){system.out.println (""+ JoinPoint.getSignature ().getName()+" Exception... {"+exception+"}"); }}Copy the code

4. Add both the aspect class and the business logic class (the target method class) to the container. Add @enableAspectJAutoProxy to the configuration class.

@EnableAspectJAutoProxy // 开启基于注解的aop模式 最关键
@Configuration
public class MainConfigOfAOP {
	 
    //业务逻辑类加入容器中
    @Bean
    public MathCalculator calculator(){
            return new MathCalculator();
    }

    //切面类加入到容器中
    @Bean
    public LogAspects logAspects(){
            return new LogAspects();
    }
}
Copy the code

5. Write test classes

@Test public void test01(){ AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfAOP.class); MathCalculator = new MathCalculator(); // mathCalculator.div(1, 1); MathCalculator mathCalculator = applicationContext.getBean(MathCalculator.class); mathCalculator.div(1, 0); applicationContext.close(); }Copy the code

So, summing up the steps above, there are only three steps to implementing an AOP:

  • 1) Add business logic components and aspect classes to the container; Tell Spring which is the Aspect class (@aspect)
  • 2) Annotate each notification method on the aspect class with a notification annotation to tell Spring when and where to run (pointcut expression)
  • 3) Enable annotation based AOP pattern; @EnableAspectJAutoProxy

AOP principle: see what component is registered in the container, when this component works, what is the function of this component?

Declarative transaction

Environment set up

Import data source, database driver, spring-JDBC module

<! <dependency> <groupId>org. Spring Framework </groupId> <artifactId> Spring JDBC </artifactId> The < version > 4.3.12. RELEASE < / version > < / dependency > <! <artifactId> c3P0 </artifactId> <version>0.9.1.2</version> </dependency> <! -- Database driver --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector- Java </artifactId> <version>5.1.44</version>  </dependency>Copy the code

Configure the data source, and the JdbcTemplate (a tool provided by Spring to simplify database operations) manipulates the data. Using the @ EnableTransactionManagement open annotation-based transaction management function; Configure the transaction manager PlatformTransactionManager to control the transaction

@ EnableTransactionManagement @ ComponentScan (" com. Atguigu. Tx) @ Configuration public class TxConfig {/ / @ Bean data source to the public DataSource dataSource() throws Exception{ ComboPooledDataSource dataSource = new ComboPooledDataSource(); dataSource.setUser("root"); dataSource.setPassword("123456"); dataSource.setDriverClass("com.mysql.jdbc.Driver"); dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test"); return dataSource; } @bean public JdbcTemplate JdbcTemplate () throws Exception{//Spring treats @Configuration special; JdbcTemplate = new JdbcTemplate(dataSource()); return jdbcTemplate; } / / registration affairs manager in a container @ Bean public PlatformTransactionManager transactionManager () throws the Exception {return new DataSourceTransactionManager(dataSource()); }}Copy the code

Annotate a method with @transactional to indicate that the current method is a Transactional method;

@Service public class UserService { @Autowired private UserDao userDao; @Transactional public void insertUser(){ userDao.insert(); //otherDao.other(); XXX system.out. println(" Insert done...") ); int i = 10/0; } } @Repository public class UserDao { @Autowired private JdbcTemplate jdbcTemplate; public void insert(){ String sql = "INSERT INTO `tbl_user`(username,age) VALUES(? ,?) "; String username = UUID.randomUUID().toString().substring(0, 5); jdbcTemplate.update(sql, username,19); }}Copy the code

Declarative transaction principles

Extension principle

The principle of spring BeanFactoryPostProcessor

BeanFactoryPostProcessorbeanFactory post processor; Called after the BeanFactory standard is initialized to customize and modify the contents of the BeanFactory; All bean definitions have been saved and loaded into the beanFactory, but the bean instance has not yet been created