约定:

一、@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的配置,可以XMLJavaConfig注解

一般推荐使用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 学习笔记的更多相关文章

  1. Spring in Action 4th 学习笔记 之 AOP

    前提:本文中的AOP仅限于Spring AOP. 先说说为什么需要AOP 最简单的一个例子就是日志记录,如果想记录一些方法的执行情况,最笨的办法就是修改每一个需要记录的方法.但这,真的很笨... 好的 ...

  2. spring in action 4 (学习笔记1)

    1.spring两个核心性质 DI(依赖注入) AOP(面向切面编程) 2.bean的生命周期

  3. 1、Spring In Action 4th笔记(1)

    Spring In Action 4th笔记(1) 2016-12-28 1.Spring是一个框架,致力于减轻JEE的开发,它有4个特点: 1.1 基于POJO(Plain Ordinary Jav ...

  4. Spring实战第八章学习笔记————使用Spring Web Flow

    Spring实战第八章学习笔记----使用Spring Web Flow Spring Web Flow是一个Web框架,它适用于元素按规定流程运行的程序. 其实我们可以使用任何WEB框架写流程化的应 ...

  5. 机器学习实战(Machine Learning in Action)学习笔记————09.利用PCA简化数据

    机器学习实战(Machine Learning in Action)学习笔记————09.利用PCA简化数据 关键字:PCA.主成分分析.降维作者:米仓山下时间:2018-11-15机器学习实战(Ma ...

  6. 机器学习实战(Machine Learning in Action)学习笔记————08.使用FPgrowth算法来高效发现频繁项集

    机器学习实战(Machine Learning in Action)学习笔记————08.使用FPgrowth算法来高效发现频繁项集 关键字:FPgrowth.频繁项集.条件FP树.非监督学习作者:米 ...

  7. 机器学习实战(Machine Learning in Action)学习笔记————07.使用Apriori算法进行关联分析

    机器学习实战(Machine Learning in Action)学习笔记————07.使用Apriori算法进行关联分析 关键字:Apriori.关联规则挖掘.频繁项集作者:米仓山下时间:2018 ...

  8. 机器学习实战(Machine Learning in Action)学习笔记————06.k-均值聚类算法(kMeans)学习笔记

    机器学习实战(Machine Learning in Action)学习笔记————06.k-均值聚类算法(kMeans)学习笔记 关键字:k-均值.kMeans.聚类.非监督学习作者:米仓山下时间: ...

  9. 机器学习实战(Machine Learning in Action)学习笔记————05.Logistic回归

    机器学习实战(Machine Learning in Action)学习笔记————05.Logistic回归 关键字:Logistic回归.python.源码解析.测试作者:米仓山下时间:2018- ...

随机推荐

  1. hdu 4961 Boring Sum(高效)

    pid=4961" target="_blank" style="">题目链接:hdu 4961 Boring Sum 题目大意:给定ai数组; ...

  2. oracle Database link 创建

    http://www.cnblogs.com/yhason/p/3735319.html

  3. CentOS6.4之图解SSH无验证双向登陆配置

    配置SSH无登陆验证,在很多场景下是非常方便的,尤其是在管理大型集群服务时,避免了繁琐的密码验证,在安全级别越高的服务器上,通常密码的设置更复杂,配置SSH,不仅可以用密钥保证节点间通信的安全性,同时 ...

  4. 了不起的 “filter(NULL IS NOT NULL)”

    经常会在执行计划中看到很奇怪的"FILTER"操作,然后看对应的执行信息是"filter(NULL IS NOT NULL)".  其实这是优化器非常聪明的“短 ...

  5. iOS之Sqlite3封装

    一.代码下载 代码下载地址 二.实例效果展示 imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="效果图二.png&q ...

  6. cocos2d-x画线

    在class HelloWorld : public cocos2d::CCLayer中添加 void draw(); 实现: void HelloWorld::draw() { CCSize s = ...

  7. 中间件监控之Apache

    补 系统架构 nginx接到请求后把请求转发到tomcat,还有种方式是转发到apache(php项目),或者其他语言的应用服务器(放置我们的项目) ngnix:是web服务器,接受和转发请求用的,不 ...

  8. nyoj116 士兵杀敌(二)树状数组 插点问线

    士兵杀敌(二) 时间限制:1000 ms  |  内存限制:65535 KB 难度:5 描述 南将军手下有N个士兵,分别编号1到N,这些士兵的杀敌数都是已知的. 小工是南将军手下的军师,南将军经常想知 ...

  9. ny2 括号配对问题

    括号配对问题 时间限制:3000 ms  |  内存限制:65535 KB 难度:3   描述 现在,有一行括号序列,请你检查这行括号是否配对.   输入 第一行输入一个数N(0<N<=1 ...

  10. centos 手动编译 fcitx 各种问题大全

    yum install ncurses-devel   tinyxml-devel sqlite-devel wget http://downloads.sourceforge.net/project ...