Three cases of @Import in Spring

We often see @Import import functionality in the Spring framework, especially at the framework level.


I'll just tell you what it can import. First, declare that @Import is a comment. There are three types of imports:

1. Import the configuration @Configuration, similar to the import xml file of spring's earlier version 2.5,

<?xml version="1.0" encoding="UTF-8"?>  
<beans xmlns="http://www.springframework.org/schema/beans"  
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
       xsi:schemaLocation="  
       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd  
       ">  
      
    <import resource="cms-validator-service.xml"/>  
    <import resource="cms-validator-dao.xml"/>  
       
</beans>  

Annotations just steal the spotlight right now, but for the same purpose, use all configurations labeled @configurationAnnotations.

Here's a quick example of how you can build a java project

Build a java main package firstCom.springAnd build subpackages separately

com.spring.service,  com.spring.service.impl, com.spring.config, com.spring.test

1.1 Establishing service interfaces

package com.spring.service;

/**
 * 
 * @author dgm
 * @describe "Log Service Interface"
 */
public interface LogService {

    void print(String message);
}

1.2 Establish service implementation classes in three cases, console, file, and database mysql

package com.spring.service.impl;

import org.springframework.stereotype.Component;
import com.spring.service.LogService;

/**
 * @author dgm
 * @describe "Log to console
 */
@Component
public class StdOutLogServiceImpl implements LogService {

	@Override
	public void print(String message) {
        System.out.println(message);
        System.out.println("Write a log to the console!");
	}
}


import java.io.File;
import java.io.FileWriter;
import java.io.IOException;

import org.springframework.stereotype.Component;
import com.spring.service.LogService;

/**
 * 
 * @author dgm
 * @describe "Log to File
 */
@Component
public class FileLogServiceImpl implements LogService {

	private static final String FILE_NAME="d://LogService.txt";
	@Override
	public void print(String message) {
		try {
			File file = new File(FILE_NAME);
			FileWriter fw = null;
			// true: Indicates that it is an append flag
			fw = new FileWriter(file, true);
			fw.write(message+"\n");
			fw.close();

	        System.out.println(message);
			System.out.println("Write log to file!");
		} catch (IOException e) {
		}
	}
}


/**
 * @author dgm
 * @describe "Log into mysql database "
 */
@Component
public class MysqlLogServiceImpl implements LogService {

	@Override
	public void print(String message) {
        System.out.println(message);
        System.out.println("Write Log to Database");
	}
}

1.3 Write configuration classes, three service implementation classes corresponding to three @Configuration

package com.spring.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.spring.service.LogService;
import com.spring.service.impl.StdOutLogServiceImpl;

@Configuration
public class StdOutConfig {

	@Bean(name="stdOutLogServiceImpl")
	public LogService stdOutLogServiceImpl(){
		return new StdOutLogServiceImpl();
	}
}


import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.spring.service.LogService;
import com.spring.service.impl.FileLogServiceImpl;

@Configuration
public class FileLogConfig {

	@Bean(name="fileLogServiceImpl")
	public LogService fileLogServiceImpl(){
		return new FileLogServiceImpl();
	}
}

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.spring.service.LogService;
import com.spring.service.impl.MysqlLogServiceImpl;

@Configuration
public class MysqlLogConfig {

	@Bean(name="mysqlLogServiceImpl")
	public LogService mysqlLogServiceImpl(){
		return new MysqlLogServiceImpl();
	}
}

Then the @Import comment came on

import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

@Configuration
@Import({StdOutConfig.class, FileLogConfig.class, MysqlLogConfig.class})
public class LogParentConfig {

}

1.4 Set up a test class to see the effect

import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import com.spring.config.LogParentConfig;
import com.spring.service.*;

/**
 * @author dgm
 * @describe "java configuration bean"
 */
public class LogConfigurationAppTest {
	public static void main(String[] args) {
		AnnotationConfigApplicationContext  context = new AnnotationConfigApplicationContext(
				LogParentConfig.class);
		//Console
		LogService obj = (LogService) context.getBean("stdOutLogServiceImpl");
		System.out.println(obj);
		obj.print("console output");
		//file
		obj = (LogService) context.getBean("fileLogServiceImpl");
		System.out.println(obj);
		obj.print("File Output");
		//mysql
		obj = (LogService) context.getBean("mysqlLogServiceImpl");
		System.out.println(obj);
		obj.print("data base mysql");
		
		context.close();
	}
}

Output Effect

 

2. Import classes that implement the ImportSelector interface or subinterface DeferredImportSelector

@Import annotation can also be configured with an ImportSelector implementation to select @Configuration classes programmatically, based on some selection criteria.

As I'll also show below, this is important because there's a lot to develop in the framework and spring extensions, so build an alternate subpackage firstCom.spring.beanandCom.spring.importSelectorAnd then set up the configuration file directory conf

2.1 ImportSelector implementation

2.1.1) Create auxiliary class APplicationProperties.javaAnd external profilesMyapp.properties

package com.spring.bean;

public class ApplicationProperties {
	private String connectionUrl;
	private String connectionName;

	public String getConnectionUrl() {
		return connectionUrl;
	}

	public void setConnectionUrl(String connectionUrl) {
		this.connectionUrl = connectionUrl;
	}

	public String getConnectionName() {
		return connectionName;
	}

	public void setConnectionName(String connectionName) {
		this.connectionName = connectionName;
	}

	@Override
	public String toString() {
		return "ApplicationProperties [connectionUrl=" + connectionUrl
				+ ", connectionName=" + connectionName + "]";
	}
}

Then set up the configuration file in the conf directoryMyapp.properties, as follows:

app.url=https://github.com/dongguangming
app.name=dongguangming

2.1.2 Establish the @Configuration configuration class

@Configuration
@PropertySource("classpath:conf/myapp.properties")
public class AppConfig {
	@Autowired
	ConfigurableEnvironment environment;

	@Bean
	ApplicationProperties appProperties() {
		ApplicationProperties bean = new ApplicationProperties();
		bean.setConnectionUrl(environment.getProperty("app.url"));
		bean.setConnectionName(environment.getProperty("app.name"));
		return bean;
	}
}

2.1.3 Establishes an import class that implements the ImportSelector interface. The value in the return list is marked @Configuration

public class LogImportSelector implements  ImportSelector{

	@Override
	public String[] selectImports(AnnotationMetadata importingClassMetadata) {
		
		    return new String[]{"com.spring.config.AppConfig","com.spring.config.LogParentConfig"};
	}

}

2.1.4 Establish a configuration class with @import capability and import an implementation class of 2.1.3

package com.spring.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

import com.spring.importSelector.LogImportSelector;

@Configuration
@Import(LogImportSelector.class)
public class LogImportSelectorConfig {

}

2.1.5 Writing test classes

 

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import com.spring.bean.ApplicationProperties;
import com.spring.config.LogImportSelectorConfig;
import com.spring.service.*;

/**
 * @author dgm
 * @describe "java configuration bean"
 */
public class LogImportSelectorConfigurationAppTest {
	public static void main(String[] args) {
		AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
				LogImportSelectorConfig.class);
		// Console
		LogService obj = (LogService) context.getBean("stdOutLogServiceImpl");
		System.out.println(obj);
		obj.print("console output");
		// file
		obj = (LogService) context.getBean("fileLogServiceImpl");
		System.out.println(obj);
		obj.print("File Output");
		// mysql
		obj = (LogService) context.getBean("mysqlLogServiceImpl");
		System.out.println(obj);
		obj.print("data base mysql");

		//
		ApplicationProperties ap = context.getBean(ApplicationProperties.class);
		System.out.println(ap);

		context.close();
	}
}

Output effect:

Good results, bean s can also be registered

There is also a variant based on annotations, and I'm also going to build a subpackage firstCom.spring.annotation

Create custom annotations:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(LogImportSelector.class)
/**
 * @author dgm
 * @describe "Customize Enable functionality
 */
public @interface EnableLogService {
	//Default log output to console
	String logType() default "stdout";

	@AliasFor("value")
	String[] basePackages() default {};

	@AliasFor("basePackages")
	String[] value() default {}; 
}

Then modify the import selector implementation class to absolutely load which bean based on the parameters passed when logging is enabled

AnnotationAttributes attributes = AnnotationAttributes
				.fromMap(importingClassMetadata.getAnnotationAttributes(
						EnableLogService.class.getName(), false));
		System.out.println(attributes);

		//Loading bean s based on log type
		String logType = attributes.getString("logType");

		if (logType.equalsIgnoreCase("StdOut")) {
			return new String[] { "com.spring.config.AppConfig",
					"com.spring.config.StdOutConfig" };
		} else if (logType.equalsIgnoreCase("File")) {
			return new String[] { "com.spring.config.AppConfig",
					"com.spring.config.FileLogConfig" };
		} else if (logType.equalsIgnoreCase("Mysql")) {
			return new String[] { "com.spring.config.AppConfig",
					"com.spring.config.MysqlLogConfig" };
		} else {
			return new String[] { "com.spring.config.AppConfig",
					"com.spring.config.LogParentConfig" };
		}

Modify the configuration class, append the custom comment @EnableLogService, and set the parameter to file (optional stdout, file, mysql)

@Configuration
//@Import(LogImportSelector.class)
@EnableLogService(logType="file")
public class LogImportSelectorConfig {

}

Modify the test class so that bean s that are no longer implemented by all three log implementations are loaded and loaded by configuration parameters

LogService obj = (LogService) context.getBean("fileLogServiceImpl");
		System.out.println(obj);
		obj.print("File Output");

 

Just because @EnableLogService(logType="file") is configured, only one log implementation bean is loaded

2.2 Implement DeferredImportSelector

public interface DeferredImportSelector extends ImportSelector {
}

But you see it's a 2.1 subinterface

The configuration class directly registered with the application context given preference over imported one. That means a bean of type T, configured in the main configuration will be used instead of a bean of the same type T from imported configuration. That applies to ImportSelector as well. On the other hand, DeferredImportSelector applies after all other configuration beans have been processed.

We can compare the differences between the two interfaces

Configuration Class Log in Main SelectorImportSelectorConfig.javaMedium increase

@Bean
	LogBean logBean() {
		return new LogBean();
	}

	@Bean(name = "fileLogServiceImpl")
	public LogService fileLogServiceImpl() {
		return new FileLogServiceImpl(" Come from LogImportSelectorConfig  ");
	}

 

In File Configuration Class FileLogConfig.java Modified to

@Bean(name="fileLogServiceImpl")
	public LogService fileLogServiceImpl(){
		return new FileLogServiceImpl("Come from  FileLogConfig");
	}

Chooser implementation class or

public class LogImportSelector implements ImportSelector  {. . . }

Execute test code

LogBean bean = context.getBean(LogBean.class);
	    bean.printMessage();

 

At this point, the interface that modifies the selector implementation is changed to DeferredImportSelector, and nothing else is changed

public class LogImportSelector implements DeferredImportSelector  {. . . }

Again = Execute the test


 

2.3 Import a class that implements the ImportBeanDefinitionRegistrar interface

You can start by looking at how and what interfaces are defined

public interface ImportBeanDefinitionRegistrar {

	public void registerBeanDefinitions(
                            AnnotationMetadata importingClassMetadata,
                            BeanDefinitionRegistry registry);

}

 This Interface is to be implemented by types that register additional bean definitions when processing @Configuration classes.

Refer to the various ways I remember registering Spring Bean as a blog post I wrote before https://blog.csdn.net/dong19891210/article/details/105798650 Do you want to take a closer look at subsection 5.2 so that you don't have to repeat the wording here?

In fact, you understand Bean, spring itself, and the derived third-party extensions, 99.99% of the problems are no longer problems!!!

 

Summary: A picture


Be sure to master 2 and 3. Writing extensions is useful, and even spring itself is heavily used.

spring operates around bean s, there are several ways to register, and the conditional choice of each

 

Finally, slowly learn to forget the xml format configuration file, which is annotated now or later, although xml configuration does not affect functionality!


 

Notes in the appendix One:


 

Reference resources:

0.  @Import Annotation in Spring Framework

https://javabeat.net/use-import-importing-javaconfig-files-spring-projects/ 

1. Spring registers advanced applications of beans with containers https://cloud.tencent.com/developer/article/1497795

Tags: Java Spring MySQL xml

Posted on Mon, 25 May 2020 16:46:45 -0700 by warriors2003