Spring in Action 4th 学习笔记
约定:
一、@Xxx Class 表示被@Xxx注解的类。同理还有@Xxx注解的字段或方法。
例如:@Bean Method。
二、@Component Class 同时代指 @Controller、@Service、@Repository。
All beans in a Spring application context are given an ID. -- 如果不指明,也会给定一个默认的ID:类名,首字母小写。
【】上面这句,不适合XML方式,因为XML方式的默认ID是全路径再加上#{n} ,例如 a.b.c.D#2 。
Spring的配置,可以XML、JavaConfig和注解。
一般推荐使用JavaConfig和注解,因为JavaConfig可以保证类型一致,重构重命名都不会影响。
@RunWith(SpringJUnit4ClassRunner.class) //测试开始时,会自动创建Spring的ApplicationContext。
@ContextConfiguration(classes=CDPlayerConfig.class) // 从什么地方加载JavaConfig。默认导包。
【】Bean在第三方库中时,无法使用注解扫描导入~
这时,可以使用JavaConfig或者XML配置。但是,建议使用JavaConfig配置,因为更强大,且类型有保证。
JavaConfig is configuration code。就是说,它不应该包含任何业务代码,也不应该被任何业务代码包含。
【】@Autowired 可以用在任何方法上,本质都是注入形参。
【】@Autowired(required=false) 这样注入失败不会异常! 但是需要判断null异常。
【】问题:如果有多个bean,那怎么选择?同时满足也会异常,需要窄化范围,见后面。
@Component 基本等同于 @Named (JSR330)
@Autowired 基本等同于 @Inject (JSR330)
纯JavaConfig:
JavaConfig 就是@Configuration Class。
如果JavaConfig需要自动扫描并创建Bean,那就再加上@ComponentScan注解。
注意,这里的扫描对象是@Component Class 。
而且,自动生成的Bean,其ID就是类名,首字母小写。(XML则是全路径再加上#{n} ,例如 a.b.c.D#2 。)
示例如下:
@Configuration // 声明这是JavaConfig,Spring会自动加载
@ComponentScan() // 自动扫描,需要指定路径,稍后详解
public Class MyConfig{
}
如果JavaConfig不需要自动扫描,那就需要在JavaConfig类中设置@Bean Method。示例如下:
@Configuration // 声明这是JavaConfig,Spring会自动加载
public Class MyConfig{
@Bean(name="youSpecifiedID")
public MyType myType(){
return new MyType(); // 看这里,创建对象!!!
}
}
继续,这种情况下(不自动扫描),怎么解决依赖注入的问题?最简单的办法如下:
@Configuration
public Class MyConfig{
@Bean(name="youSpecifiedID") // 默认ID是类型首字母小写
public TypeA typeA(){
return new TypeA();
} @Bean()
public TypeB typeB(){
return new TypeB( typeA() ); // 最简单直接的办法,就是调用@Bean Method
} }
注意,上面这样直接调用@Bean Mehtod的方式,不会每次都调用@Bean Method!Spring会拦截该调用,而直接注入Bean(这里是typeA)。
JavaConfig还可以导入其他的JavaConfig或XML,如下:
@Configuration
@import( Config1.class, Config2.class ) // 导入任意多个其他的JavaConfig
@importResource( "classpath:xxx.xml" ) // 导入XML
public Class ConfigAll{
/* your Code here */
}
XML导入XML,使用<import resource="another.xml" />。
XML导入JavaConfig,使用<bean class="xx.xx.JavaConfig" />。这样Spring创建该bean的时候会自动扫描并导入相关数据。
【】【】XML配置,可以使用spring tool suite (https://spring.io/tools/sts)
该工具还可以检查大多数XML的配置。
【】【】XML的依赖注入。
【】【】构造方法:<bean ...><constructor-arg ref="refID" /></bean> 注意引用是ref,如果是字面值,使用value!!!如 value="Hello"。
传入null:<constructor-arg><null/></constructor-arg>
【】【】c名称空间:<bean ... c:形参名-ref="refID" /> 注意,如果是字面值,使用【c:形参名】即可。形参位置也一样。
注意,需要导入名称空间。
形参名不方便,如果压缩文件,会破坏形参名。
可以使用形参位置【_n】。如果只有一个形参,n可以省略。
【】集合List和Set
<list>
<value></value>
<value></value>
</list>
<list>
<ref bean="refID"/>
<ref bean="refID"/>
</list>
【】property
【】p名称空间。
【】util名称空间。
<util:constant> References a public static field on a type
<util:list> java.util.List
<util:map> java.util.Map
<util:properties> java.util.Properties
<util:property-path> References a bean property (or nested property)
<util:set> java.util.Set
高级注入
不同的环境下可能需要注入不同的Bean,例如DataSource,有dev、qa和prod环境,该怎么解决?
笨办法:配置不同的XML,在编译时选择使用哪个。(例如,可以通过Maven Profiles选择。)
缺点:不同的环境需要不同的编译!!
Spring的解决方案:在运行时决定选择使用哪个。
找出需要选择的Bean,放到一个或多个Profile中,然后Spring根据不同的Profile自动选择创建的Bean。
JavaConfig中:
① 在不自动扫描的JavaConfig中,可以使用@Profile注解到@Bean Method上。
② 在自动扫描的JavaConfig中,需要将@Profile注解到@Component Class上。
注意:没有被@Profile的@Bean Method或@Component Class,各种环境均被创建!!!
在XML中:
① <beans ... profile="dev">
注意,是beans,根节点。这样当前XML中的所有Bean都在dev Profile下创建。
② <beans profile="dev"><bean/>...<bean/></beans>
<beans profile="prod"><bean/>...<bean/></beans>
注意,这里不是根节点。
Spring怎么判断Profile?
两个地方:spring.profiles.default, spring.profiles.active
Spring会先检查spring.profiles.active的值,有则用;没有再去检查spring.profiles.default的值,有则用,无则没有Profile。
Spring怎么去设置Profile?
There are several ways to set these properties:
As initialization parameters on DispatcherServlet
As context parameters of a web application
As JNDI entries
As environment variables
As JVM system properties
Using the @ActiveProfiles annotation on an integration test class
例如,在web.xml中
<!-- 【】设置context的默认profile -->
<context-param>
<param-name>spring.profiles.default</param-name>
<param-value>dev</param-value>
</context-param> <!-- 【】设置servlet的默认Profile -->
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<init-param>
<param-name>spring.profiles.default</param-name>
<param-value>dev</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
上面,设置了default Profile,给dev用。其他情况下,可以通过设置active来覆盖default。
测试时,可以通过@ActiveProfiles("dev")注解到测试类上,设置并激活spring.profiles.active。
【】上面是Spring3的方式,Spring4提供了更强大的方式。
@Conditional 注解到@Bean Method上面。
@Conditional(ConditionImpl.class) 【】这里的ConditionImpl就是Condition接口的实现类,只有一个方法,就是match,用于判断是否符合条件。
public interface Condition {
boolean matches(ConditionContext ctxt, AnnotatedTypeMetadata metadata);
}
可以通过ConditionContext实参获取Environment对象,从而判断是否包含指定的Property。
public class MagicExistsCondition implements Condition {
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Environment env = context.getEnvironment();
return env.containsProperty("magic"); //【】判断环境中是否包含magic Property。
}
}
只有符合的情况下,被@Conditional注解的@Bean method才会创建Bean。
【】注意,还可以通过实参(ConditionContext和AnnotatedTypeMetadata),获取其他对象,从而用于判断。
【】Spring4,@Profile已经被重构,新版基于@Conditional实现。
【】【】解决NoUniqueBeanDefinitionException问题。
【】【】办法一:指定primary bean。
@Primary 注解到@Component Class或者 @Bean Method上。
<bean ... primary="true"/>
【】注意,一种类型只能指定一个。
【】缺点:不能自由选择!
【】【】办法二:@Qualifier 注解到@Autowired或者@Inject。
@Autowired
@Qualifier("iceCream")
public void setDessert(Dessert dessert) {
this.dessert = dessert;
}
【】说明,@Qualifier可以注解到@Component上,意思是将Bean的qualifier设为注解的值。如无该注解,默认类名首字母小写。
【】说明,@Qualifier也可以注解到@Bean Method上。相当于注解到@Component Class上。
因为@ComponentScan时使用@Component,没有@ComponentScan时则使用@Bean。
【】【】默认,spring中所有bean都被创建为singleton。(单例)。
spring scope:singleton、prototype、session(web)、request(web)。
@Scope("prototype") 注解到@Component上,或<bean scope="prototype">。
@Scope("prototype") 注解到@Bean上。
【】SSH,应对app请求,无状态,可以考虑request scope。
【】购物车,可以使用session scope。
【】【】想知道的是,application context中,如何保证 bean id 不冲突??
@Service都是单例,实际上,也是因为它都是以形参接收参数吧。且类的属性都是单例的。
给@Service@Scope("singleton")类中的方法@Autowired注入@Scope("session")的bean时:
① @Service一开始就被spring创建,而@Scope("session")则等到有请求时才会被创建,之前怎么办?
② @Scope("session")的bean,应该是每个session一个,而@Service只有一个,应该怎么选择?
【】这时,可以使用代理,让spring注入代理,然后根据实际情况选择调用的bean。这就是@Scope的属性proxyMode。
当proxyMode=ScopedProxyMode.INTERFACES时,只能代理接口的实现。
当proxyMode=ScopedProxyMode.TARGET_CLASS时,使用CGLIB,可以代理任何类。
注解时:@Scope(value="session", proxyMode=ScopedProxyMode.TARGET_CLASS)
XML时: <bean ... scope="session"></bean>
注意,XML时,默认使用CGLIB代理,如果想使用JDK代理, <aop:scoped-proxy proxy-target-class="false" />
注意,XML使用proxyMode,需要导入aop空间。
【】【】【】一些值,不想硬编码,而是在运行时载入。
Spring有两种办法:property placeholders、Spring Expression Language (SpEL)。二者类似,但用途和表现不同。
【】【】理解什么是placeholder propery:${ xxx } 这里${} 就是placeholder,里面的xxx就是property。
property placeholders:
该方法是从一个source加载property到Environment对象中,然后就可以使用Environment对象调用加载的property。
【】@PropertySource("classpath:/com/soundsystem/app.properties") 可以注解到JavaConfig中。
然后通过env.getProperty()即可获取需要的内容。
String getProperty(String key)
String getProperty(String key, String defaultValue) // 【】注意,可以设置默认值
T getProperty(String key, Class<T> type)
T getProperty(String key, Class<T> type, T defaultValue) // 【】注意,可以设置默认值 另外,如果要求必须提供某个property,那可以使用env.getRequiredProperty(key),这样,如果不提供,就会异常。
另外,如果想检查某个property是否存在,可以使用env.containsProperty(key)。
另外,如果想将某个property转成类对象,可以使用env.getPropertyAsClass(key,xx.class) 除了property,Environment同样提供了获取Profile的方法。
String[] getActiveProfiles()
String[] getDefaultProfiles()
boolean acceptsProfiles(String... profiles) //如果Environment支持给定的Profiles,就true。
除了Environment,还可以使用${key}的方式注入。
【】【】【】使用@Value("${key}")注解。【注意与使用@Value("#{}")的区别】
public BlankDisc(@Value("${disc.title}") String title, @Value("${disc.artist}") String artist) {
this.title = title;
this.artist = artist;
}
使用这种方式(@Value("${key}"))时,需要配置PropertyPlaceholderConfigurer bean或PropertySourcesPlaceholderConfigurer bean。
从3.1开始,推荐使用PropertySourcesPlaceholderConfigurer bean。
在JavaConfig中配置:
@Bean
public static PropertySourcesPlaceholderConfigurer placeholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
在XML中配置:
<context:property-placeholder /> 注意,直接返回PropertySourcesPlaceholderConfigurer bean。
【】【】Spring Expression Language (SpEL)
The first thing to know is that SpEL expressions are framed with #{ ... }, much as property placeholders are framed with ${ ... }.
SpEL使用#{ ... }。
#{ 12 } 数字
#{ 9.8E4 } 98000
#{ 'abc你好' } String
#{ true }
#{ T(System).currentTimeMillis() }
【】T(System) 意思是导入java.lang.System。
#{ beanID.property }
【】根据beanID调用某个bean的属性
#{ beanID.method() }
【】根据beanID调用某个bean的method()
#{ beanID.getName().toUpperCase() }
【】这里假定beanID对应的bean有getName()方法,且返回String,那可以继续调用toUpperCase()方法。
但是,如果返回null,那就异常了!怎么解决?
解决办法:type-safe operator 【?.】
#{ beanID.getName()?.toUpperCase() } 这样,如果getName()返回null,整体就返回null。 #{jukebox.songs[4].title}
【】调用集合或数组
【】SpEL针对操作集合或数组,提供了一个选择操作符。【.?[]】
用法:#{jukebox.songs.?[artist eq 'Aerosmith']} 集合或数组中的元素的artist属性值为"Aerosmith"的,返回列表。
另外,针对操作集合或数字,还提供了【.^[]】【.?[]】 。前者是选择第一个匹配的元素,后者是选择最后一个匹配的元素。
用法:#{jukebox.songs.^[artist eq 'Aerosmith']} #{jukebox.songs.$[artist eq 'Aerosmith']}
另外,还提供了一个projection operator 【.![]】,该操作符用于投影符合的元素属性到一个新的集合。
用法:#{jukebox.songs.![title]}
【小结】
SpEL针对集合或数组的操作:
.?[] 选择所有匹配的元素(集合);
.^[] 选择第一个匹配的元素;
.$[] 选择最后一个匹配的元素。
.![] 选择属性,投影到新集合。
【】这些操作可以组合!!!就是链式编程而已。
【】【】由于都是String,所以,尽量少用 简用 SpEL!
【】【】【】使用@Value("#{}")注入【注意与使用@Value("${key}")的区别】
public BlankDisc( @Value("#{systemProperties['disc.title']}") String title, @Value("#{systemProperties['disc.artist']}") String artist) {
this.title = title;
this.artist = artist;
}
【】【】【】XML中使用SpEL。
① <property ... value="#{}">
② <constructor-arg value="#{}">
③ p-namespace
④ c-namespace entry
【】如果想调用Class,需要使用T() operator。T()操作符主要用于调用静态方法和常量!!!
【】【】SpEL操作符的分类:
数学计算【+, -, *, /, %, ^】
比较【<, lt, >, gt, ==, eq, <=, le, >=, ge】
逻辑【and, or, not】
条件【?: (ternary 三元运算符), ?: (Elvis)】
正则【matches】 #{scoreboard.score > 1000 ? "Winner!" : "Loser"}
#{disc.title ?: 'Rattle and Hum'} 【】变种用法,如果null,则返回'Rattle and Hum'。Elvis operator。
Spring in Action 4th 学习笔记的更多相关文章
- Spring in Action 4th 学习笔记 之 AOP
前提:本文中的AOP仅限于Spring AOP. 先说说为什么需要AOP 最简单的一个例子就是日志记录,如果想记录一些方法的执行情况,最笨的办法就是修改每一个需要记录的方法.但这,真的很笨... 好的 ...
- spring in action 4 (学习笔记1)
1.spring两个核心性质 DI(依赖注入) AOP(面向切面编程) 2.bean的生命周期
- 1、Spring In Action 4th笔记(1)
Spring In Action 4th笔记(1) 2016-12-28 1.Spring是一个框架,致力于减轻JEE的开发,它有4个特点: 1.1 基于POJO(Plain Ordinary Jav ...
- Spring实战第八章学习笔记————使用Spring Web Flow
Spring实战第八章学习笔记----使用Spring Web Flow Spring Web Flow是一个Web框架,它适用于元素按规定流程运行的程序. 其实我们可以使用任何WEB框架写流程化的应 ...
- 机器学习实战(Machine Learning in Action)学习笔记————09.利用PCA简化数据
机器学习实战(Machine Learning in Action)学习笔记————09.利用PCA简化数据 关键字:PCA.主成分分析.降维作者:米仓山下时间:2018-11-15机器学习实战(Ma ...
- 机器学习实战(Machine Learning in Action)学习笔记————08.使用FPgrowth算法来高效发现频繁项集
机器学习实战(Machine Learning in Action)学习笔记————08.使用FPgrowth算法来高效发现频繁项集 关键字:FPgrowth.频繁项集.条件FP树.非监督学习作者:米 ...
- 机器学习实战(Machine Learning in Action)学习笔记————07.使用Apriori算法进行关联分析
机器学习实战(Machine Learning in Action)学习笔记————07.使用Apriori算法进行关联分析 关键字:Apriori.关联规则挖掘.频繁项集作者:米仓山下时间:2018 ...
- 机器学习实战(Machine Learning in Action)学习笔记————06.k-均值聚类算法(kMeans)学习笔记
机器学习实战(Machine Learning in Action)学习笔记————06.k-均值聚类算法(kMeans)学习笔记 关键字:k-均值.kMeans.聚类.非监督学习作者:米仓山下时间: ...
- 机器学习实战(Machine Learning in Action)学习笔记————05.Logistic回归
机器学习实战(Machine Learning in Action)学习笔记————05.Logistic回归 关键字:Logistic回归.python.源码解析.测试作者:米仓山下时间:2018- ...
随机推荐
- hdu 4961 Boring Sum(高效)
pid=4961" target="_blank" style="">题目链接:hdu 4961 Boring Sum 题目大意:给定ai数组; ...
- oracle Database link 创建
http://www.cnblogs.com/yhason/p/3735319.html
- CentOS6.4之图解SSH无验证双向登陆配置
配置SSH无登陆验证,在很多场景下是非常方便的,尤其是在管理大型集群服务时,避免了繁琐的密码验证,在安全级别越高的服务器上,通常密码的设置更复杂,配置SSH,不仅可以用密钥保证节点间通信的安全性,同时 ...
- 了不起的 “filter(NULL IS NOT NULL)”
经常会在执行计划中看到很奇怪的"FILTER"操作,然后看对应的执行信息是"filter(NULL IS NOT NULL)". 其实这是优化器非常聪明的“短 ...
- iOS之Sqlite3封装
一.代码下载 代码下载地址 二.实例效果展示 imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="效果图二.png&q ...
- cocos2d-x画线
在class HelloWorld : public cocos2d::CCLayer中添加 void draw(); 实现: void HelloWorld::draw() { CCSize s = ...
- 中间件监控之Apache
补 系统架构 nginx接到请求后把请求转发到tomcat,还有种方式是转发到apache(php项目),或者其他语言的应用服务器(放置我们的项目) ngnix:是web服务器,接受和转发请求用的,不 ...
- nyoj116 士兵杀敌(二)树状数组 插点问线
士兵杀敌(二) 时间限制:1000 ms | 内存限制:65535 KB 难度:5 描述 南将军手下有N个士兵,分别编号1到N,这些士兵的杀敌数都是已知的. 小工是南将军手下的军师,南将军经常想知 ...
- ny2 括号配对问题
括号配对问题 时间限制:3000 ms | 内存限制:65535 KB 难度:3 描述 现在,有一行括号序列,请你检查这行括号是否配对. 输入 第一行输入一个数N(0<N<=1 ...
- centos 手动编译 fcitx 各种问题大全
yum install ncurses-devel tinyxml-devel sqlite-devel wget http://downloads.sourceforge.net/project ...