Combining Autowired and Service annotations
public interface IUser { void say(); } @Service public class Student implements IUser { @Override public void say() { System.out.println("I'm a student"); } } @Component @Order(value = 3) public class Entry implements CommandLineRunner { public Log log = LogFactory.getLog(Entry.class); @Autowired IUser user; @Override public void run(String... args) throws Exception { user.say(); } }
If you need to access injected variables in the constructor, then the location of Autowired should be placed on the constructor
@Component @Order(value = 3) public class TestService { private final IUser user; @Autowired public void TestService (IUser user) { user.say(); } }
Custom injection scan scope
It should be noted that when Springboot scans packages, the default is to scan down from the startup class (usually Application) directory, which means that if the bean is not in the lower layer of the Application directory, it will not be scanned.
This situation will prompt:
Description: Field xxx in xxxxxx required a bean of type 'xxxxxx' that could not be found. Action: Consider defining a bean of type 'xxxxxxxxxxxxxx' in your configuration.
But this is not impossible to change, we can manually specify the scan range:
@SpringBootApplication @ComponentScan(basePackages={"springbootdemo.basic","anotherspringbootdemo.basic"}) public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
Don't forget to add the original directory to the scope list, as well as the package scope of the startup class.
In addition, this ComponentScan does not have to be placed on the startup class, as long as it can be scanned.
By way of Configuration
The "cross-domain" injection method can also be implemented through Configuration (that is, the package is not in a scope)
/** * Springboot will scan for classes marked with Configuration annotation * For methods marked with Bean annotations in this class, the return value will be used as the injected item * As for the injection item of this Bean, return is in the method. */ @Configuration public class TestConfig{ @Bean public IUser user(){ return new Teacher(); } // Beans with dependencies are also very simple // This IDepartment depends on IUser @Bean public IDepartment(){ return new Development(user()); } } /* call */ public class TestClass{ @Autowired IUser user; public void run(String... args) throws Exception { user.say(); } }
Although the above Configuration solves "cross-domain" injection, the Configuration annotation still requires to be placed in the calling project.
Many times when we need to rely on a third-party jar package and want to achieve automatic injection, we don't want to manually write the Configuration. After all, if the jar package is referenced in multiple places, it needs to be handled in every place.
Can it be done once and for all?
When using the framework in Springboot, such as ES, we found that although ElasticSearchTemplate is not declared, it can be used directly
Here is a good explanation https://www.jianshu.com/p/346cac67bfcc
Suppose the third-party project is ProjectA and the application side is ProjectB
Now ProjectA has class TestTemplate
package ProjectA; public class TestTemplate { public void test() { System.out.println("GO TEST"); } }
ProjectB needs to inject and use TestTemplate. Of course, you must first add maven dependencies (ignore) and call logic
package ProjectB; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.CommandLineRunner; import org.springframework.stereotype.Component; import springbootdemo.common.TestTemplate; @Component public class Entry implements CommandLineRunner { @Autowired private TestTemplate aa; @Override public void run(String... args) throws Exception { aa.test(); } }
At this time, if you run ProjectB, you will definitely report an error, because the injection result of TestTemplate cannot be found, even if you add annotations to TestTemplate.
We directly give a simple solution
①Create a new automatic configuration class TestAutoConfiguration in ProjectA
package ProjectA; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class TestAutoConfiguration { @Bean @ConditionalOnMissingBean public TestTemplate testTemplate(){ return new TestTemplate(); } }
②Create a directory META-INF/spring.factories under the resource directory src/main/resources of ProjectA
content:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
ProjectA.TestAutoConfiguration
Execute now, everything is OK!