(摘自 Pro Spring MVC With Web Flow,Deinum,Deinum,Sernells,Yates,Ladd,Vanfletern,Apress)
一、@Configuration 注解注意事项:
1、Configuration 类可以是 abstract 的,但不可以是 final 的,因为 spring 容器动态创建其子类。
二、applicationContext加载路径:
1、spring加载配置文件采取ant的正则表达式,classpath: 表示从项目根目录加载,classpath*:表示从当前层次,classpath**:表示从当前目录及其子目录。file:表示文件系。
http:表示web程序的根目录。
2、FileSystemXmlApplicationContext 只能从本地文件系统加载,不能加载web上的配置文件。
三、用配置类配置:
1、可以用配置类配置,例如:
@Configuration
public class ApplicationContextConfiguration {
@Bean
public AccountRepository accountRepository() {
return new AccountRepository();
}
@Bean
public TransactionRepository transactionRepository() {
return new TransactionRepository();
}
@Bean
public MoneyTransferService moneyTransferService() {
return new MoneyTransferServiceImpl();
}
}
加载的时候用new AnnotationConfigApplicationContext(ApplicationContextConfiguration.class);
加载。bean的名称就是方法的名称。
不过很少看到在项目中这么干。
2、配置类使用component-scan:
只需要加上注解
org.springframework.context.annotation.ComponentScan
配置类就支持扫描。
例如:
@ComponentScan(basePackages = {
"packagea",
"packageb" })
小心:把扫描路径设置为整个classpath,或过于靠近根路径,如com.apress之类的不是一个好想法,会导致服务启动的时间过长。相信各位程序员一定有过调试时一个项目启动10多秒的时候吧,所以最好别这么设置。
四、component-scan:
1、component-scan目前支持的5种注解:
org.springframework.stereotype.Component
org.springframework.stereotype.Service
org.springframework.stereotype.Repository
org.springframework.stereotype.Controller
org.springframework.context.annotation.Configuration
五、scope(作用域)
1、spring作用域有7种:singleton prototype thread request session globalSession application。
(1) singleton:单例,spring默认的,用于无状态的bean,就是那种方法都是给个参数,返回个值,无副作用的bean。
(2) prototype:原型,需要一个bean的时候就new 一个
(3) thread:线程,如题,在线程范围内需要bean的时候就绑定一个到当前线程,线程结束,destroy bean 。
(4) request:请求,绑定在javax.servlet.ServletRequest中,请求over,就destroy。
(5) session:会话,绑定在javax.servlet.HttpSession,session destroy,bean destroy。
(6) globalSession:全局会话,在一个portlet 范围内有效。portlet 由jsr-168定义,jsr-268更新,类似于一个子application的东东。如果没有portlet,那么就跟session是一样的。
(7) application:应用程序,绑定在javax.servlet.ServletContext,和singleton的bean很像,一个application里面只有一个bean。老实说,除了被绑定对象不同,看不出和singleton bean 有何不同。
六、Profiles(配置)
1、从spring3.1开始引入,使我们的application(程序)对于不同的environment(环境)使用不同的configuration(配置),增强了程序的可移植性与可测试性。例如可以对 测试 云环境 配置不同的profiles。指定 profile,则只加载这个 profile 中的 bean
2、使用之前,需要告诉程序激活那个configuration。通过设置spring.profiles.active来告诉系统。在web环境下,作为一个 servlet initialization parameter 或者一个 web context parameter 参数进行设置。在哪里设置?嗯,还是多加一句:在web.xml中。
3、用配置类加 profile
只需加注解
org.springframework.context.annotation.Profile
//示例
@Configuration
@Profile(value = "test")
//用法
System.setProperty("spring.profiles.active","test")
多一句,很多 Profile 一般定义在 配置类 的静态内部类上,例如:
@Configuration
public class ApplicationContextConfiguration {
@Bean
public Class1 bean1() {
return new Class1();
}
@Configuration
@Profile(value = "test")
public static class TestConfig {
@Bean
public Class2 class2() {
return new TestClass2();
}
}
@Configuration
@Profile(value = "local")
public static class LocalConfig {
@Bean
public Class2 class2() {
return new LocalClass2();
}
}
}
七、***增加内容
书中spring 版本为2.X
spring 3.x 中开始支持的注解:
1、org.springframework.transaction.annotation.EnableTransactionManagement (启用TransactionManagement)
启用特性后,支持@Transaction注解,从而自动提交与回滚。
外带提一句,spring 官方文档对其 Transaction management 这样介绍:
1、为model提供统一的 transaction api。如 java transaction api (JTA) ,hibernate,jdbc,java persistence api (JPA),java data api (JDA)。
2、支持声明式事物管理 。(declarative transaction management)
3、相较于 JTA 等,提供更简单的 API。
4、对spring 的数据访问抽象进行了出色的整合。
实际使用中也确实方便不少
2、org.springframework.context.annotation.EnableAspectJAutoProxy (启用切面自动代理)
启用特性后,支持@Aspect
注解。
用法
//方式一:注解类
@Configuration
@EnableAspectJAutoProxy
public class AppConfig {
@Bean
public FooService fooService() {
return new FooService();
}
@Bean
public MyAspect myAspect() {
return new MyAspect();
}
}
//方式二:注解+扫描
//方式一:注解类
@Component
public class FooService {
// various methods
}
//实际使用,定义一个注解
@Aspect public class MyAspect { //切片对象 * FooService+.*(..) 的意思是返回任意方法的 FooService 类中的所有任意参数的方法。 //其他的切面定义方法参照 java 反射API @Before("execution(* FooService+.*(..))") public void advice() { // advise FooService methods as appropriate } }
3、org.springframework.scheduling.annotation.EnableAsync(启用异步支持)
提供类似于<task:的功能,用法:(1)注解方式:
@Configuration
@EnableAsync
public class AppConfig implements AsyncConfigurer {
@Bean
public MyAsyncBean asyncBean() {
return new MyAsyncBean();
}
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(7);
executor.setMaxPoolSize(42);
executor.setQueueCapacity(11);
executor.setThreadNamePrefix("MyExecutor-");
executor.initialize();
return executor;
}
}
(2) xml方式:<beans>
<task:annotation-config executor="myExecutor"/>
<task:executor id="myExecutor" pool-size="7-42" queue-capacity="11"/>
<bean id="asyncBean" class="com.foo.MyAsyncBean"/>
</beans>
在xml中使用,需引入命名空间xmlns:task="http://www.springframework.org/schema/task"
在schemaLocation中引入http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd
4、org.springframework.cache.annotation.EnableCaching
允许缓存,与xml配置中<catch:* 对应。
用法:
@Configuration
@EnableCaching
public class AppConfig {
@Bean
public MyService myService() {
// configure and return a class having @Cacheable methods
return new MyService();
}
@Bean
public CacheManager cacheManager() {
// configure and return an implementation of Spring's CacheManager SPI
SimpleCacheManager cacheManager = new SimpleCacheManager();
cacheManager.addCaches(Arrays.asList(new ConcurrentMapCache("default")));
return cacheManager;
}
}
在上述用法中,必须有一个返回 CacheManager 的 cacheManager 方法。或者
@Configuration
@EnableCaching
public class AppConfig implements CachingConfigurer {
@Bean
public MyService myService() {
// configure and return a class having @Cacheable methods
return new MyService();
}
@Bean
@Override
public CacheManager cacheManager() {
// configure and return an implementation of Spring's CacheManager SPI
SimpleCacheManager cacheManager = new SimpleCacheManager();
cacheManager.addCaches(Arrays.asList(new ConcurrentMapCache("default")));
return cacheManager;
}
@Bean
@Override
public KeyGenerator keyGenerator() {
// configure and return an implementation of Spring's KeyGenerator SPI
return new MyKeyGenerator();
}
}
上述方法继承了 CachingConfigurer ,必须实现 cacheManager 和 keyGenerator 两个方法。
5、org.springframework.context.annotation.EnableLoadTimeWeaving(允许时间监控)
用法
@Configuration @EnableLoadTimeWeaving public class AppConfig { // application-specific @Bean definitions ... }或者
@Configuration @EnableLoadTimeWeaving public class AppConfig implements LoadTimeWeaverConfigurer { @Override public LoadTimeWeaver getLoadTimeWeaver() { MyLoadTimeWeaver ltw = new MyLoadTimeWeaver(); ltw.addClassTransformer(myClassFileTransformer); // ... return ltw; } }对应的XML配置:
<beans>
<context:load-time-weaver weaverClass="com.acme.MyLoadTimeWeaver"/>
</beans>
这个东东对于日志记录很有用,用法就是,嗯!,还是提一句:getBena("loadTimeWeaver")。呵呵。6、org.springframework.scheduling.annotation.EnableScheduling(启用调度器)
启动后可以使用定时任务调度。
用法
@Configuration
@EnableScheduling
public class AppConfig{
}
启用后将注册启用有
@Scheduled
注解的bean
例如:
public class MyTask{
@Scheduled(fixedRate=1000)
public void work(){
System.out.println("balabala")
}
}
相应的配置类:@Configuration
@EnableScheduling
public class AppConfig{
@Bean
public MyTask myTask{
return new MyTask();
}
}
以上配置会使new MyTask().work() 每1秒钟执行一次。
用法2:
@Configuration
@EnableScheduling
public class AppConfig implements SchedulingConfigurer {
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.setScheduler(taskExecutor());
}
@Bean(destroyMethod="shutdown")
public Executor taskExecutor() {
return Executors.newScheduledThreadPool(100);
}
}
需要实现 configureTasks 和 taskExecutor 两个方法。
更复杂的实现方法:
@Configuration
@EnableScheduling
public class AppConfig implements SchedulingConfigurer {
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.setScheduler(taskScheduler());
taskRegistrar.addTriggerTask(
new Runnable() {
public void run() {
myTask().work();
}
},
new CustomTrigger()
);
}
@Bean(destroyMethod="shutdown")
public Executor taskScheduler() {
return Executors.newScheduledThreadPool(42);
}
@Bean
public MyTask myTask() {
return new MyTask();
}
}
这里又添加了一个Task对应的xml配置
<beans>
<task:annotation-config scheduler="taskScheduler"/>
<task:scheduler id="taskScheduler" pool-size="42"/>
<task:scheduled ref="myTask" method="work" fixed-rate="1000"/>
<bean id="myTask" class="com.foo.MyTask"/>
</beans>
7、org.springframework.web.servlet.config.annotation.EnableWebMvc(允许mvc)
激活MVC特性,注册所有有@Controller注解的类
@Configuration
@EnableWebMvc
@ComponentScan(
basePackageClasses = { MyConfiguration.class },
excludeFilters = { @Filter(type = FilterType.ANNOTATION, value = Configuration.class) }
)
public class MyConfiguration {
}
注意 上面的ComponentScan注解,里面有excludeFilters ={@Filter(type=FilterType.ANNOTATION,value=Configuration.class)},把本配置文件排除在外。要进行进一步的定制,可以实现WebMvcConfigurer 接口或者继承WebMvcConfigurerAdapter类。
例子:
@Configuration
@EnableWebMvc
@ComponentScan(
basePackageClasses = { MyConfiguration.class },
excludeFilters = { @Filter(type = FilterType.ANNOTATION, value = Configuration.class) }
)
public class MyConfiguration extends WebMvcConfigurerAdapter {
@Override
public void registerFormatters(FormatterRegistry formatterRegistry) {
formatterRegistry.addConverter(new MyConverter());
}
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(new MyHttpMessageConverter());
}
...
}
八、面向切面编程
几个概念:切面(Aspect)、连接点(join point)、通知(Advice)、切入点(Pointcut)
切面(Aspect):横穿几个切面的类,用org.aspectj.lang.annotation.Aspect 注解标示。
连接点(join point):程序执行过程中的一个点,在spring中,就是一个方法的执行。
通知(Advice):切入点发生的行为,常见的@Before @After @AfterThrowing @AfterReturning @Around
切入点(Pointcut):声明的所有符合条件的连接点,是一个Advice的集合。通过org.aspectj.lang.annotation.Pointcut 注解标识。
例子:
@Aspect
public class AfterThrowingExample {
@AfterThrowing(
pointcut="com.xyz.myapp.SystemArchitecture.dataAccessOperation()",
throwing="ex")
public void doRecoveryActions(DataAccessException ex) {
// ...
}
@AfterThrowing("com.xyz.myapp.SystemArchitecture.dataAccessOperation()")
public void doRecoveryActions() {
// ...
}
@Pointcut("execution(* com.xyz.someapp.service.*.*(..))")
public void businessService() {}
}
注意上面的执行表达式(execution expression):
语法:
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern) throws-pattern?)
解释下:
modifiers-pattern 访问权限匹配
ret-type-pattern 返回类型匹配
declaring-type-pattern 申明类型匹配(含包名)
name-pattern 方法名称匹配
param-pattern 参数匹配
throws-pattern 异常声明匹配
execute expression 中.. 表示所有 . 表示一个单词,*表示任意字母
九、实际web程序的入口:
1、org.springframework.web.servlet.DispatcherServlet
2、org.springframework.web.context.ContextLoaderListener