如何加载 @Configuration class 而 @ComponentScan 没有注释相同的 class
How can @Configuration class is loaded while @ComponentScan is not annotated for the same class
我遇到了这个 tutorial,它展示了如何使用 H2 嵌入式数据库
spring 应用程序,它工作正常,没有任何问题。
但是看了代码没看懂怎么配置classDBConfig
正在被发现并将其视为 ApplicationContext 的配置 class,因此可以创建里面的 bean。
请注意,它没有在 AnnotationConfigApplicationContext()
中用作参数,并且 @ComponentScan
和 @Configuration
没有在同一个 class 中注释。
如下所示 class Application
@ComponentScan(basePackages = "com.zetcode")
public class Application {
private static final Logger logger = LoggerFactory.getLogger(Application.class);
public static void main(String[] args) {
// the application context is taking as argument the same Class
var ctx = new AnnotationConfigApplicationContext(Application.class);
var app = ctx.getBean(Application.class);
app.run();
ctx.close();
}
@Autowired
private JdbcTemplate jdbcTemplate;
private void run() {
var sql = "SELECT * FROM cars";
var cars = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(Car.class));
cars.forEach(car -> logger.info("{}", car));
}
}
和classDBConfig
@Configuration
public class DBConfig {
@Bean
public DataSource dataSource() {
var builder = new EmbeddedDatabaseBuilder();
var db = builder
.setType(EmbeddedDatabaseType.H2) // HSQL or DERBY
.addScript("db/schema.sql")
.addScript("db/data.sql")
.build();
return db;
}
@Bean
public JdbcTemplate createJdbcTeamplate() {
var template = new JdbcTemplate();
template.setDataSource(dataSource());
return template;
}
}
我还做了一些 JUnit 测试,我发现 DBConfig
已经创建,因此在其中定义了 Bean。
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes=Application.class)
public class EmbeddedTest {
@Autowired
private DBConfig dbConfig;
@Autowired
private DataSource dataSource;
@Test
public void test() {
assertNotNull(dbConfig);
assertNotNull(dataSource);
}
}
我不得不做一些 调试 以弄清楚 spring 如何处理上述情况。
由于我们没有向我们的应用程序上下文提供已配置的 Class,Spring 将使用 @ComponentScan
来获取它。 如何? 通过注释中提供的包 com.zetcode
。它扫描 com.zetcode
下的包和所有子包搜索 类:
src
├───main
│ ├───java
│ │ └───com
│ │ └───zetcode
│ │ │ Application.java
│ │ ├───config
│ │ │ DBConfig.java
│ │ └───model
│ │ Car.java
│ └───resources
│ │ logback.xml
│ └───db
│ create-db.sql
│ insert-data.sql
└───test
└───java
因此,它会找到 3 个:Application
、DBConfig
、Car
并针对每个它查看它是否是候选组件。在我们的示例中,通用 Bean 仅为 Application
DBConfig
。一旦确定了它们,下一步就是检查 @Bean
方法。对于每一个识别出来的对象,它都会创建专用的 Bean。最后它会自动装配。
我遇到了这个 tutorial,它展示了如何使用 H2 嵌入式数据库 spring 应用程序,它工作正常,没有任何问题。
但是看了代码没看懂怎么配置classDBConfig
正在被发现并将其视为 ApplicationContext 的配置 class,因此可以创建里面的 bean。
请注意,它没有在 AnnotationConfigApplicationContext()
中用作参数,并且 @ComponentScan
和 @Configuration
没有在同一个 class 中注释。
如下所示 class Application
@ComponentScan(basePackages = "com.zetcode")
public class Application {
private static final Logger logger = LoggerFactory.getLogger(Application.class);
public static void main(String[] args) {
// the application context is taking as argument the same Class
var ctx = new AnnotationConfigApplicationContext(Application.class);
var app = ctx.getBean(Application.class);
app.run();
ctx.close();
}
@Autowired
private JdbcTemplate jdbcTemplate;
private void run() {
var sql = "SELECT * FROM cars";
var cars = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(Car.class));
cars.forEach(car -> logger.info("{}", car));
}
}
和classDBConfig
@Configuration
public class DBConfig {
@Bean
public DataSource dataSource() {
var builder = new EmbeddedDatabaseBuilder();
var db = builder
.setType(EmbeddedDatabaseType.H2) // HSQL or DERBY
.addScript("db/schema.sql")
.addScript("db/data.sql")
.build();
return db;
}
@Bean
public JdbcTemplate createJdbcTeamplate() {
var template = new JdbcTemplate();
template.setDataSource(dataSource());
return template;
}
}
我还做了一些 JUnit 测试,我发现 DBConfig
已经创建,因此在其中定义了 Bean。
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes=Application.class)
public class EmbeddedTest {
@Autowired
private DBConfig dbConfig;
@Autowired
private DataSource dataSource;
@Test
public void test() {
assertNotNull(dbConfig);
assertNotNull(dataSource);
}
}
我不得不做一些 调试 以弄清楚 spring 如何处理上述情况。
由于我们没有向我们的应用程序上下文提供已配置的 Class,Spring 将使用 @ComponentScan
来获取它。 如何? 通过注释中提供的包 com.zetcode
。它扫描 com.zetcode
下的包和所有子包搜索 类:
src
├───main
│ ├───java
│ │ └───com
│ │ └───zetcode
│ │ │ Application.java
│ │ ├───config
│ │ │ DBConfig.java
│ │ └───model
│ │ Car.java
│ └───resources
│ │ logback.xml
│ └───db
│ create-db.sql
│ insert-data.sql
└───test
└───java
因此,它会找到 3 个:Application
、DBConfig
、Car
并针对每个它查看它是否是候选组件。在我们的示例中,通用 Bean 仅为 Application
DBConfig
。一旦确定了它们,下一步就是检查 @Bean
方法。对于每一个识别出来的对象,它都会创建专用的 Bean。最后它会自动装配。