1.泛化@Qualifier
在很多情况下,仅仅使用注解就足够了。而且这一点在注解服务更为泛化的情况下更为有用。比如说,开发者需要提供一个线下的目录的话,可以参考如下的定义:
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface Offline {
}
之后的使用不要指定值了,自动装载配置如下:
public class MovieRecommender {
@Autowired
@Offline
private MovieCatalog offlineCatalog;
// ...
}
XML中的配置也较为简单,如下:
<bean class="example.SimpleMovieCatalog">
<qualifier type="Offline"/>
<!-- inject any dependencies required by this bean -->
</bean>
2.@ComponentScan注解指定扫描包
@Configuration
@ComponentScan(basePackages = "org.example")
public class AppConfig {
...
}
3.component的filter 使用component的filter可以不需要注解来扫描类
<context:component-scan base-package="com.xhlx.finance.budget" >
<context:include-filter type="regex" expression=".service.*"/>
</context:component-scan>
or
@Configuration
@ComponentScan(basePackages = "org.example",
includeFilters = @Filter(type = FilterType.REGEX, pattern = ".*Stub.*Repository"),
excludeFilters = @Filter(Repository.class))
public class AppConfig {
...
}
4.@profile
首先说一下为什么要使用这个@profile注解。@profile注解是spring提供的一个用来标明当前运行环境的注解。我们正常开发的过程中经常遇到的问题是,开发环境是一套环境,qa测试是一套环境,线上部署又是一套环境。这样从开发到测试再到部署,会对程序中的配置修改多次,尤其是从qa到上线这个环节,让qa的也不敢保证改了哪个配置之后能不能在线上运行。 为了解决上面的问题,我们一般会使用一种方法,就是配置文件,然后通过不同的环境读取不同的配置文件,从而在不同的场景中跑我们的程序。 那么,spring中的@profile注解的作用就体现在这里。在spring使用DI来依赖注入的时候,能够根据当前制定的运行环境来注入相应的bean。最常见的就是使用不同的DataSource了。
@Configuration
@Profile(value = "dev")
@Component
public class Chinese implements MoveFactor {
@Override
public void speak() {
System.out.println("我是中国人");
}
}
修改@ActiveProfiles的值改变环境
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = App.class)
@ActiveProfiles("dev")
public class SpringTest {
@Autowired
Person p;
@Test
public void testProfile(){
p.speak();
}
}
最后提一下,如果是在web的后台项目中如何进行设置。这个时候我们通过xml的方式进行设置:
<context-param>
<param-name>spring.profiles.active</param-name>
<param-value>DOUBLEUPMINT</param-value>
</context-param>
5.AplicationEnvent 容器事件
继承ContextRefreshedEvent,ContextStartedEvent,ContextStoppedEvent,ContextClosedEvent,RequestHandledEvent实现自定义事件
public class BlackListEvent extends ApplicationEvent {
private final String address;
private final String test;
public BlackListEvent(Object source, String address, String test) {
super(source);
this.address = address;
this.test = test;
}
// accessor and other methods...
}
继承ApplicationEvent:自定义的事件类 实现ApplicationListener :用于监听事件 实现ApplicationEventPublisherAware :用于发布事件
6.@Async异步方法
异步方法定义
@Async
public Future<String> asyncMethodWithReturnType() {
System.out.println("Execute method asynchronously - "
+ Thread.currentThread().getName());
try {
Thread.sleep(5000);
return new AsyncResult<String>("hello world !!!!");
} catch (InterruptedException e) {
//
}
return null;
}
使用future获取异步方法返回结果
public void testAsyncAnnotationForMethodsWithReturnType()
throws InterruptedException, ExecutionException {
System.out.println("Invoking an asynchronous method. "
+ Thread.currentThread().getName());
Future<String> future = asyncAnnotationExample.asyncMethodWithReturnType();
while (true) { ///这里使用了循环判断,等待获取结果信息
if (future.isDone()) { //判断是否执行完毕
System.out.println("Result from asynchronous process - " + future.get());
break;
}
System.out.println("Continue doing something else. ");
Thread.sleep(1000);
}
}
7.实现validator可以对bean进行校验
public class PersonValidator implements Validator {
/**
* This Validator validates *just* Person instances
*/
public boolean supports(Class clazz) {
return Person.class.equals(clazz);
}
public void validate(Object obj, Errors e) {
ValidationUtils.rejectIfEmpty(e, "name", "name.empty");
Person p = (Person) obj;
if (p.getAge() < 0) {
e.rejectValue("age", "negativevalue");
} else if (p.getAge() > 110) {
e.rejectValue("age", "too.darn.old");
}
}
}