④ 使用@ComponentScan
如下所示,定义了@Configuration
的类还可以同时使用@ComponentScan
注解:
@Configuration @ComponentScan("com.jane.app.services") public class AppConfig { // various @Bean definitions ... }
⑤ 使用Environment API
外部环境中的值可以通过注入Environment
来获取,如下所示:
@Configuration public class AppConfig { @Autowired Environment env; @Bean public MyBean myBean() { MyBean myBean = new MyBean(); myBean.setName(env.getProperty("bean.name")); return myBean; } }
⑥ 使用@PropertySource
@PropertySource可以根据需要加载指定的配置文件(@ConfigurationProperties 默认从全局配置文件获取配置),将配置文件中的属性注入到系统环境中。
@Configuration @PropertySource("classpath:/com/jane/app.properties") public class AppConfig { @Inject Environment env; @Bean public MyBean myBean() { return new MyBean(env.getProperty("bean.name")); } }
⑦ @Value注解
⑥中我们使用env.getProperty("bean.name")
来获取beanName,那么我们也可以直接使用@Value注解来获取环境中的属性。
@Configuration @PropertySource("classpath:/com/jane/app.properties") public class AppConfig { @Value("${bean.name}") String beanName; @Bean public MyBean myBean() { return new MyBean(beanName); } }
⑧ @Import注解
类似Spring XML中配置的<import>
标签一样,@Configuration配置类可以使用@Import注解进行组合。
⑧ @Import注解 类似Spring XML中配置的<import>标签一样,@Configuration配置类可以使用@Import注解进行组合。 @Co
⑨ @Profile
@Configuration类可以用@Profile注解标记,以指示只有在给定的一个或多个配置文件处于活动状态时才应处理它们。
@Profile("development") @Configuration public class EmbeddedDatabaseConfig { @Bean public DataSource dataSource() { // instantiate, configure and return embedded DataSource } } @Profile("production") @Configuration public class ProductionDatabaseConfig { @Bean public DataSource dataSource() { // instantiate, configure and return production DataSource } }
前面提到过,也可以在方法级别与@Bean注解一起使用,如下所示:
@Configuration public class ProfileDatabaseConfig { @Bean("dataSource") @Profile("development") public DataSource embeddedDatabase() { ... } @Bean("dataSource") @Profile("production") public DataSource productionDatabase() { ... } }
⑩ @ImportResource引入外部xml配置
可以使用@ImportResource注解引入外部的spring xml配置,xml中定义的bean可以自动被注入。
@Configuration @ImportResource("classpath:/com/jane/database-config.xml") public class AppConfig { @Inject DataSource dataSource; // from XML @Bean public MyBean myBean() { // inject the XML-defined dataSource bean return new MyBean(this.dataSource); } }
(11) 使用嵌套的@Configuration
@Configuration public class AppConfig { @Inject DataSource dataSource; @Bean public MyBean myBean() { return new MyBean(dataSource); } @Configuration static class DatabaseConfig { @Bean DataSource dataSource() { return new EmbeddedDatabaseBuilder().build(); } } }
类似于上述实例时,只需要注册AppConfig 。因为AppConfig
与DatabaseConfig
已经清晰,故而不需要再使用@Import(DatabaseConfig.class)
。
(12) Test支持
spring-test模块中的Spring TestContext framework提供了@ContextConfiguration,其可以接受一个component 类数组,通常是@Configuration或者@Component类。
@RunWith(SpringRunner.class) @ContextConfiguration(classes = {AppConfig.class, DatabaseConfig.class}) public class MyTests { @Autowired MyBean myBean; @Autowired DataSource dataSource; @Test public void test() { // assertions against myBean ... } }
(13) @Enable注解
使用@Enable注解使内置的Spring features 起作用,如@EnableAsync、@EnableScheduling、@EnableTransactionManagement、@EnableAspectJAutoProxy、@EnableWebMvc。
(14)@Configuration注解的一些约束
必须是类,不能是工厂方法返回的实例;
必须不能是final的,除非proxyBeanMethods设置为false;
配置类必须是非本地的(即可能不在方法中声明),native 标注的方法;
嵌套的@Configuration必须是static;
@Bean方法不能返回任何configuration 类。
【4】功能类注解
① @ControllerAdvice
① ControllerAdvice定义
一种特殊的Component类,其内部声明的@ExceptionHandler、@InitBinder或者@ModelAttribute可以被@Controller类共享。
在SpringMVC常见组件之HandlerAdapter分析中我们从源码角度分析了,当ControllerAdviceBean定义了@ExceptionHandler、@InitBinder或者@ModelAttribute方法时,其如何被应用。
声明了@ControllerAdvice注解的类可以直接被声明为Spring Bean或者通过类路径自动扫描注入。这些bean可以通过实现Ordered接口或者使用@Order/@Priority注解来进行排序,前者(实现接口)优先于后者(注解)。在系统运行时,就会根据其order值进行使用。不过值得一提的是,PriorityOrdered接口在排序上的优先级低于Ordered。当然,如果@ControllerAdvice bean被声明为一个request-scoped或者session-scoped bean,Ordered就将不那么重要。
为了处理异常,通常在第一个@ControllerAdvice bean中声明一个标注了@ExceptionHandler注解的方法。对于模型属性和数据绑定初始化,也就是@ModelAttribute和@InitBinder方法将会遵循order顺序。
对于@ExceptionHandler方法,在特定advice bean的方法中,根异常匹配比只匹配当前异常更可取。但是,与低优先级通知bean上的任何匹配(无论是根级别还是具体异常级别)相比,高优先级通知上的具体异常匹配仍然是首选的。因此,请按照相应的顺序在高优先级的advice bean上声明primary root exception映射。
默认情况下,@ControllerAdvice类的方法是全局性的,针对所有controller起作用。可以使用诸如annotations、basePackageClasses或者basePackages来定义目标范围。如果定义了多个筛选条件,那么将会以“OR”的逻辑含义起作用。这个判断逻辑可以从如下源码展示:
// org.springframework.web.method.HandlerTypePredicate#test @Override public boolean test(Class<?> controllerType) { // 如果没有选择器,直接返回true if (!hasSelectors()) { return true; } // 否则根据选择器定义范围进行判断 else if (controllerType != null) { for (String basePackage : this.basePackages) { if (controllerType.getName().startsWith(basePackage)) { return true; } } for (Class<?> clazz : this.assignableTypes) { if (ClassUtils.isAssignable(clazz, controllerType)) { return true; } } for (Class<? extends Annotation> annotationClass : this.annotations) { if (AnnotationUtils.findAnnotation(controllerType, annotationClass) != null) { return true; } } } return false; }
② ControllerAdvice 源码
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Component public @interface ControllerAdvice { // 定义扫描包数组 @AliasFor("basePackages") String[] value() default {}; //扫描的包路径,如下所示 // @ControllerAdvice(basePackages = "org.my.pkg")} // @ControllerAdvice(basePackages = {"org.my.pkg", "org.my.other.pkg"})} @AliasFor("value") String[] basePackages() default {}; // 扫描的包的类型数组 Class<?>[] basePackageClasses() default {}; // 适应的类型-controller只要符合其中一个类型,将会被作为目标对象 Class<?>[] assignableTypes() default {}; // 作用目标-注解类型数组。controller只要标注了数组中一个注解,将会被作为目标对象 Class<? extends Annotation>[] annotations() default {}; }
使用@ControllerAdvice 对异常处理可以参考博文SpringMVC中异常处理与ControllerAdvice捕捉全局异常