Springboot Dependency Injection Notes

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!

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324727761&siteId=291194637