(摘自 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)注解方式:
(2) xml方式:@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; } }
在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>
在schemaLocation中引入xmlns:task="http://www.springframework.org/schema/task"
4、org.springframework.cache.annotation.EnableCachinghttp://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd
允许缓存,与xml配置中<catch:* 对应。
用法:
在上述用法中,必须有一个返回 CacheManager 的 cacheManager 方法。@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; } }
或者
上述方法继承了 CachingConfigurer ,必须实现 cacheManager 和 keyGenerator 两个方法。@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(); } }
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配置:这个东东对于日志记录很有用,用法就是,嗯!,还是提一句:getBena("loadTimeWeaver")。呵呵。<beans> <context:load-time-weaver weaverClass="com.acme.MyLoadTimeWeaver"/> </beans>
6、org.springframework.scheduling.annotation.EnableScheduling(启用调度器)
启动后可以使用定时任务调度。
用法
@Configuration @EnableScheduling public class AppConfig{ }
启用后将注册启用有
注解的bean@Scheduled
例如:
相应的配置类:public class MyTask{ @Scheduled(fixedRate=1000) public void work(){ System.out.println("balabala") } }
以上配置会使new MyTask().work() 每1秒钟执行一次。@Configuration @EnableScheduling public class AppConfig{ @Bean public MyTask myTask{ return new MyTask(); } }
用法2:
需要实现 configureTasks 和 taskExecutor 两个方法。@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); } }
更复杂的实现方法:
这里又添加了一个Task@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(); } }
对应的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注解的类
注意 上面的ComponentScan注解,里面有excludeFilters ={@Filter(type=FilterType.ANNOTATION,value=Configuration.class)},把本配置文件排除在外。@Configuration @EnableWebMvc @ComponentScan( basePackageClasses = { MyConfiguration.class }, excludeFilters = { @Filter(type = FilterType.ANNOTATION, value = Configuration.class) } ) public class MyConfiguration { }
要进行进一步的定制,可以实现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() { // ... }
注意上面的执行表达式(execution expression):@Pointcut("execution(* com.xyz.someapp.service.*.*(..))") public void businessService() {} }
语法:
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