arakoodev / FlySpring

Developer-friendly Spring Boot flavor. Supercharged cli "flyfly" to make you fall in love with Java again
MIT License
7 stars 7 forks source link

experiment with turning off component autoscan #47

Open sandys opened 1 year ago

sandys commented 1 year ago

create a spring boot application that turns off component scan entirely and loads all components (including the default spring boot beans and components) explicitly.

To create a Spring Boot application that turns off component scan entirely and loads all components explicitly, you can follow these steps:

  1. Create a new Spring Boot project using the Spring Initializr or your favorite IDE.

  2. In the src/main/java folder, create a new package named com.example.manualconfig.

  3. Inside the com.example.manualconfig package, create a new class named ManualConfigApplication with the following content:

package com.example.manualconfig;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;

@SpringBootApplication
@ComponentScan(basePackages = {})
public class ManualConfigApplication {

    public static void main(String[] args) {
        SpringApplication.run(ManualConfigApplication.class, args);
    }
}

The @ComponentScan(basePackages = {}) annotation with an empty array disables the default component scanning behavior.

  1. Now, you need to explicitly define all the beans and components you want to use in your application. For example, create a new class named AppConfig inside the com.example.manualconfig package with the following content:
package com.example.manualconfig;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;

@Configuration
@EnableWebMvc
public class AppConfig {

    // Define your beans and components here
    @Bean
    public MyService myService() {
        return new MyService();
    }
}

In this example, we have defined a MyService bean. You can add more beans and components as needed.

  1. Create a class named MyService inside the com.example.manualconfig package:
package com.example.manualconfig;

public class MyService {

    public String getMessage() {
        return "Hello from MyService!";
    }
}
  1. Now, you can use the MyService bean in your application. For example, create a new class named MyController inside the com.example.manualconfig package with the following content:
package com.example.manualconfig;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MyController {

    private final MyService myService;

    @Autowired
    public MyController(MyService myService) {
        this.myService = myService;
    }

    @GetMapping("/")
    public String hello() {
        return myService.getMessage();
    }
}
  1. Finally, run the ManualConfigApplication class as a Java application. You should see the Spring Boot application start up without any component scanning. When you access the root URL (http://localhost:8080), you should see the message "Hello from MyService!".

Remember that you need to explicitly define all the beans and components you want to use in your application. This includes any Spring Boot auto-configuration classes that you want to use.

list all the spring boot autoconfiguration classes that are used by default and add them to the previous example

Listing all the Spring Boot auto-configuration classes used by default is not feasible, as the list is extensive and depends on the dependencies you have added to your project. However, I can show you how to find the auto-configuration classes used in your project and add them to the previous example.

  1. First, run your Spring Boot application with the --debug flag. This will print the auto-configuration report in the console. You can do this by adding the following line to the main method in ManualConfigApplication:
System.setProperty("spring.boot.verbose", "true");
  1. Run your Spring Boot application and check the console output. You will see a section called "Positive matches" that lists all the auto-configuration classes that have been applied to your project.

  2. Now, you can add the required auto-configuration classes to your AppConfig class using the @Import annotation. For example, if you want to add DataSourceAutoConfiguration and JdbcTemplateAutoConfiguration, you can modify the AppConfig class as follows:

package com.example.manualconfig;

import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;

@Configuration
@EnableWebMvc
@Import({DataSourceAutoConfiguration.class, JdbcTemplateAutoConfiguration.class})
public class AppConfig {

    // Define your beans and components here
    @Bean
    public MyService myService() {
        return new MyService();
    }
}
  1. If you need to exclude any auto-configuration classes, you can use the @EnableAutoConfiguration annotation with the exclude attribute in your ManualConfigApplication class:
package com.example.manualconfig;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;

@SpringBootApplication
@EnableAutoConfiguration(exclude = {SomeAutoConfiguration.class})
@ComponentScan(basePackages = {})
public class ManualConfigApplication {

    public static void main(String[] args) {
        SpringApplication.run(ManualConfigApplication.class, args);
    }
}

Replace SomeAutoConfiguration.class with the auto-configuration class you want to exclude.

Remember that you need to add the required dependencies to your project for the auto-configuration classes to work. For example, if you want to use DataSourceAutoConfiguration, you need to add the spring-boot-starter-jdbc dependency to your project.

assume it is a minimal application with spring boot webflux with hibernate and groovy templates. please list all the autoconfiguration classes and add it to the previous example

Assuming you have a minimal Spring Boot application with WebFlux, Hibernate, and Groovy templates, you would need to add the following dependencies to your pom.xml or build.gradle file:

For Maven:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-webflux</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-groovy-templates</artifactId>
    </dependency>
    <!-- Add your database driver dependency here -->
</dependencies>

For Gradle:

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-webflux'
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.springframework.boot:spring-boot-starter-groovy-templates'
    // Add your database driver dependency here
}

Now, let's list the auto-configuration classes for WebFlux, Hibernate, and Groovy templates and add them to the AppConfig class:

package com.example.manualconfig;

import org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration;
import org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAutoConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
import org.springframework.boot.autoconfigure.web.reactive.WebFluxAutoConfiguration;
import org.springframework.boot.autoconfigure.web.reactive.error.ErrorWebFluxAutoConfiguration;
import org.springframework.boot.autoconfigure.web.reactive.function.client.ClientHttpConnectorAutoConfiguration;
import org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.web.reactive.config.EnableWebFlux;

@Configuration
@EnableWebFlux
@Import({
        WebFluxAutoConfiguration.class,
        ErrorWebFluxAutoConfiguration.class,
        ClientHttpConnectorAutoConfiguration.class,
        WebClientAutoConfiguration.class,
        JpaRepositoriesAutoConfiguration.class,
        HibernateJpaAutoConfiguration.class,
        GroovyTemplateAutoConfiguration.class
})
public class AppConfig {

    // Define your beans and components here
    @Bean
    public MyService myService() {
        return new MyService();
    }
}

This configuration imports the auto-configuration classes for WebFlux, Hibernate, and Groovy templates. Note that you might need to adjust the configuration based on your specific requirements and additional dependencies.

Keep in mind that this is a minimal setup, and depending on your application's requirements, you might need to add more auto-configuration classes or customize the existing ones. You can always refer to the Spring Boot documentation and the spring.factories file in the spring-boot-autoconfigure JAR for a complete list of auto-configuration classes.

please create a complete example

Here's a complete example of a Spring Boot application with WebFlux, Hibernate, and Groovy templates, with component scanning disabled and auto-configuration classes imported explicitly.

  1. Update your pom.xml with the required dependencies:
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-webflux</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-groovy-templates</artifactId>
    </dependency>
    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
        <scope>runtime</scope>
    </dependency>
</dependencies>
  1. Create the ManualConfigApplication class:
package com.example.manualconfig;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;

@SpringBootApplication
@ComponentScan(basePackages = {})
public class ManualConfigApplication {

    public static void main(String[] args) {
        SpringApplication.run(ManualConfigApplication.class, args);
    }
}
  1. Create the AppConfig class:
package com.example.manualconfig;

import org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration;
import org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAutoConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
import org.springframework.boot.autoconfigure.web.reactive.WebFluxAutoConfiguration;
import org.springframework.boot.autoconfigure.web.reactive.error.ErrorWebFluxAutoConfiguration;
import org.springframework.boot.autoconfigure.web.reactive.function.client.ClientHttpConnectorAutoConfiguration;
import org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.web.reactive.config.EnableWebFlux;

@Configuration
@EnableWebFlux
@Import({
        WebFluxAutoConfiguration.class,
        ErrorWebFluxAutoConfiguration.class,
        ClientHttpConnectorAutoConfiguration.class,
        WebClientAutoConfiguration.class,
        JpaRepositoriesAutoConfiguration.class,
        HibernateJpaAutoConfiguration.class,
        GroovyTemplateAutoConfiguration.class
})
public class AppConfig {

    // Define your beans and components here
    @Bean
    public MyService myService() {
        return new MyService();
    }
}
  1. Create the MyService class:
package com.example.manualconfig;

public class MyService {

    public String getMessage() {
        return "Hello from MyService!";
    }
}
  1. Create the MyController class:
package com.example.manualconfig;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MyController {

    private final MyService myService;

    @Autowired
    public MyController(MyService myService) {
        this.myService = myService;
    }

    @GetMapping("/")
    public String hello() {
        return myService.getMessage();
    }
}
  1. Create an application.properties file in the src/main/resources folder with the following content:
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect

This configuration sets up an in-memory H2 database for the application.

  1. Run the ManualConfigApplication class as a Java application. You should see the Spring Boot application start up without any component scanning. When you access the root URL (http://localhost:8080), you should see the message "Hello from MyService!".

This is a minimal example, and you might need to adjust the configuration based on your specific requirements and additional dependencies.