spring-framework-reference阅读笔记(一)
Spring Framework Runtime
首先需要对Spring FrameWok框架有个直观的认识
Java日志框架的发展史
在读到Spring依赖JCL的时候,对Java的日志系统做点普及!
最 早出现的日志框架是apache提供的log4j,使用最为广泛,成为了Java日志的事实上的标准;然而当时Sun公司在jdk1.4中增加了 JUL(java.util.logging),企图对抗log4j,于是造成了混乱,当然此时也有其它的一些日志框架的出现,如simplelog等, 简直是乱上加乱。
解决这种混乱的方案出现了:抽象出一个接口层:于是开源社区提供了commons-logging,被称为JCL。抽象时参考了log4j、JUL、simplelog,对它们进行了适配或转接,这样就一统江湖了。
看 上去现在已经非常完美了,但好景不长,log4j的作者(Ceki Gülcü)觉得JCL不够优秀,他要搞出一套更优雅的出来,于是slf4j就出现了,并且亲自实现了一个亲子——logback(有点,老子又回来了的 感觉^_^)。好吧,确实更优雅了,但混乱局面又出现了,之前使用JCL的怎么办呢,于是Ceki Gülcü在slf4j又对JCL作了桥接转换,然而事情还没完,Ceki Gülcü又回来拯救自己的“大阿哥”——log4j,于是log4j2就诞生了,同时log4j2也加进了slf4j体系中。
PS:SLF4J是在Compile绑定实现的,而JCL是Runtime时绑定的。
Spring中如何使用日志系统
- 使用JCL
由于Spring-core依赖JCL,所以可以直接配置JCL的实现,比如log4j:<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.14</version>
</dependency> - 使用SLF4J
如果你想使用SLF4J需要三步来做:先排除JCL<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.1.2.RELEASE</version>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>使用SLF4J来桥接JCL,因此首先需要引用jcl-over-slf4j
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>1.5.8</version>
</dependency>这时,spring-core调用的JCL API将桥接到了SLF4J。
最后再引入SLF4J的组合,这个组合有比较多,你参考官网,如使用SLF4J-LOG4J<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.7</version>
</dependency>建议使用SLF4J,因为JCL的Runtime绑定再与别的框架一起使用时可能出现不兼容的情况。
Spring资源
- Resource
Spring的Resource接口以及父接口,如下public interface Resource extends InputStreamSource { boolean exists(); boolean isOpen(); URL getURL() throws IOException; File getFile() throws IOException; Resource createRelative(String relativePath) throws IOException; String getFilename(); String getDescription(); }
public interface InputStreamSource { InputStream getInputStream() throws IOException; }Resource接口的实现由以下几类:
- ClassPathResource可用来获取类路径下的资源文件。假设我们有一个资源文件test.txt在类路径下,我们就可以通过给定对应资源文件在类路径下的路径path来获取它,new ClassPathResource(“test.txt”)。
- FileSystemResource 可用来获取文件系统里面的资源。我们可以通过对应资源文件的文件路径来构建一个FileSystemResource。 FileSystemResource还可以往对应的资源文件里面写内容,当然前提是当前资源文件是可写的,这可以通过其isWritable()方法来 判断。FileSystemResource对外开放了对应资源文件的输出流,可以通过getOutputStream()方法获取到。
- UrlResource可用来代表URL对应的资源,它对URL做了一个简单的封装。通过给定一个URL地址,我们就能构建一个UrlResource。
- ByteArrayResource是针对于字节数组封装的资源,它的构建需要一个字节数组。
- ServletContextResource 是针对于ServletContext封装的资源,用于访问ServletContext环境下的资源。ServletContextResource持 有一个ServletContext的引用,其底层是通过ServletContext的getResource()方法和 getResourceAsStream()方法来获取资源的。
- InputStreamResource是针对于输入流封装的资源,它的构建需要一个输入流。
- ResourceLoader
Spring定义了ResourceLoader接口来加载资源public interface ResourceLoader { Resource getResource(String location); }
所有的“application context”都实现了ResourceLoader接口,但他们的getResource方法返回的都是相应的Resource,如 ClassPathXmlApplicationContext返回的是 ClassPathResource,FileSystemXmlApplicationContext返回的是 FileSystemResource,WebApplicationContext返回的是ServletContextResource等等,如:
Resource template = ctx.getResource("some/resource/path/myTemplate.txt");
但如果你想使用FileSystemXmlApplicationContext返回ClassPathResource怎么办呢?那就加前缀了,如:
Resource template = ctx.getResource("classpath:some/resource/path/myTemplate.txt");
常用的前缀有classpath、file、http、ftp等,如:
classpath:com/myapp/config.xml
file:///data/config.xml
http://myserver/logo.png这
里我们先挑一个DefaultResourceLoader来讲。DefaultResourceLoader在获取Resource时采用的是这样的策
略:首先判断指定的location是否含有“classpath:”前缀,如果有则把location去掉“classpath:”前缀返回对应的
ClassPathResource;否则就把它当做一个URL来处理,封装成一个UrlResource进行返回;如果当成URL处理也失败的话就把
location对应的资源当成是一个ClassPathResource进行返回。ResourceLoader resourceLoader=new DefaultResourceLoader();
Resource resource=resourceLoader.getResource("/a.xml");
System.out.println(resource.exists()); - ApplicationContext
但是ApplicationContext不会因为Resource的不同而相互转换,如ApplicationContext ctx = new FileSystemXmlApplicationContext("classpath:conf/appContext.xml");
Ctx仍然是FileSystemXmlApplicationContext,而不会是ClassPathXmlApplicationContext。
PS:classpath*是加载多个资源,而且可以使用通配符。
Spring IOC
- BeanFactory 是获取bean的接口,而ApplicationContext是BeanFactory的子接口,它增加了更多企业级操作。 ApplicationConext可以看做是IOC的container,它装载配置资源,并根据配置的逻辑来装配各部件,实现用户的业务。
- 配置有三种方式:Annotation-based(Spring2.5支持)、Java-based(Spring3.0)、XML-based配置。
- XML-based方式,XML可以使用import引用别的XML
<beans>
<import resource="services.xml"/>
<import resource="resources/messageSource.xml"/>
<import resource="/resources/themeSource.xml"/> <bean id="bean1" class="..."/>
<bean id="bean2" class="..."/>
</beans>import时注意路径,而且引用的xml必须是合法的Spring Schema,因此必须包含<beans/>。同时,也可以通过ApplicationContext的构造函数传入多个资源文件达到一样的效果。
- bean 的定义设计到的字段:class、name、scope、constructor arguments、properties、autowiring mode、lazy-initialization mode、initialization method、destruction method。
- Bean 可以使用name、id来唯一标示,name和id也可以同时使用,如果bean definition只有一个class,也可以不用任何标示。但有时只有name和id仍然不够个性化命名,而且name和id必须遵循Java的命名 规范,因此别名就营运而生了。
<alias name="fromName" alias="toName"/>
- bean的定义示例
- 构造函数bean
<bean id="exampleBean" class="examples.ExampleBean"/>
<bean name="anotherExample" class="examples.ExampleBeanTwo"/>这是使用默认构造函数,如果是自己定义函数,需要使用constructor-arg指定入参。PS:如果内部静态类需要用“$”符号,如com.example.Foo$Bar。
- 静态工厂bean
<bean id="clientService"
class="examples.ClientService"
factory-method="createInstance"/>
public class ClientService {
private static ClientService clientService = new ClientService();
private ClientService() {} public static ClientService createInstance() {
return clientService;
}
}如果静态工厂需要参数呢?后面在DI时再细说。
- 实例工厂bean
<!-- the factory bean, which contains a method called createInstance() -->
<bean id="serviceLocator" class="examples.DefaultServiceLocator">
<!-- inject any dependencies required by this locator bean -->
</bean> <!-- the bean to be created via the factory bean -->
<bean id="clientService"
factory-bean="serviceLocator"
factory-method="createClientServiceInstance"/>
public class DefaultServiceLocator { private static ClientService clientService = new ClientServiceImpl();
private DefaultServiceLocator() {} public ClientService createClientServiceInstance() {
return clientService;
}
}实例工厂不像静态工厂,它必须需要一个实例,因此必须定义一个bean,这不难理解的。如上面实例的serviceLocator,在clientService的bean中通过使用factory-bean来设置,而删除了class属性。
PS:理论上静态工厂的bean也可以像实例工厂那样配置,因为我认为static既属于类也属于实例,但我的DEMO没通过,其实在JAVA代码中也不建议使用实例对象去访问类的静态方法,因此Spring更规范化了。
- 构造函数bean
- 依赖注入(DI)
DI分为两类:基于构造器的注入和基于Setter的注入,静态工厂和实例工厂都归属于构造器注入。- 构造器注入
package x.y; public class Foo { public Foo(Bar bar, Baz baz) {
// ...
} }<beans>
<bean id="foo" class="x.y.Foo">
<constructor-arg ref="bar"/>
<constructor-arg ref="baz"/>
</bean> <bean id="bar" class="x.y.Bar"/> <bean id="baz" class="x.y.Baz"/>
</beans>PS:这里需要对bean的参数 (arg)做个说明:它先按照配置出现的顺序来注入,因为默认的value是当String来处理的,但当发现类型不匹配,它会按照类型类匹配,如果还不行就需要手动指定index,或者使用参数名,但 如果使用参数名,为了防止被编译器优化需要使用 @ConstructorProperties来annotate。如
package examples; public class ExampleBean { // Fields omitted @ConstructorProperties({"years", "ultimateAnswer"})
public ExampleBean(int years, String ultimateAnswer) {
this.years = years;
this.ultimateAnswer = ultimateAnswer;
} }order定义
<bean id="exampleBean" class="examples.ExampleBean">
<constructor-arg value="7500000"/>
<constructor-arg value="42"/>
</bean>type定义
<bean id="exampleBean" class="examples.ExampleBean">
<constructor-arg type="int" value="7500000"/>
<constructor-arg type="java.lang.String" value="42"/>
</bean>index定义
<bean id="exampleBean" class="examples.ExampleBean">
<constructor-arg index="0" value="7500000"/>
<constructor-arg index="1" value="42"/>
</bean>name定义
<bean id="exampleBean" class="examples.ExampleBean">
<constructor-arg name="years" value="7500000"/>
<constructor-arg name="ultimateAnswer" value="42"/>
</bean>静态工厂注入
public class ExampleBean { // a private constructor
private ExampleBean(...) {
...
} // a static factory method; the arguments to this method can be
// considered the dependencies of the bean that is returned,
// regardless of how those arguments are actually used.
public static ExampleBean createInstance (
AnotherBean anotherBean, YetAnotherBean yetAnotherBean, int i) { ExampleBean eb = new ExampleBean (...);
// some other operations...
return eb;
} }<bean id="exampleBean" class="examples.ExampleBean" factory-method="createInstance">
<constructor-arg ref="anotherExampleBean"/>
<constructor-arg ref="yetAnotherBean"/>
<constructor-arg value="1"/>
</bean> <bean id="anotherExampleBean" class="examples.AnotherBean"/>
<bean id="yetAnotherBean" class="examples.YetAnotherBean"/> - Setter注入
public class ExampleBean { private AnotherBean beanOne;
private YetAnotherBean beanTwo;
private int i; public void setBeanOne(AnotherBean beanOne) {
this.beanOne = beanOne;
} public void setBeanTwo(YetAnotherBean beanTwo) {
this.beanTwo = beanTwo;
} public void setIntegerProperty(int i) {
this.i = i;
} }<bean id="exampleBean" class="examples.ExampleBean">
<!-- setter injection using the nested ref element -->
<property name="beanOne">
<ref bean="anotherExampleBean"/>
</property> <!-- setter injection using the neater ref attribute -->
<property name="beanTwo" ref="yetAnotherBean"/>
<property name="integerProperty" value="1"/>
</bean> <bean id="anotherExampleBean" class="examples.AnotherBean"/>
<bean id="yetAnotherBean" class="examples.YetAnotherBean"/>
- 构造器注入
- idref
用于<constructor-arg/> 或者 <property/>,使用方式同value,只是增加了校验idref的bean存不存在,如<bean id="theTargetBean" class="..."/> <bean id="theClientBean" class="...">
<property name="targetName">
<idref bean="theTargetBean" />
</property>
</bean>等同于
<bean id="theTargetBean" class="..." /> <bean id="client" class="...">
<property name="targetName" value="theTargetBean" />
</bean>两者注入的都是“theTargetBean”字符串,但前者会校验theTargetBean标识的bean是否存在,而后者不校验。
- 内部类注入
<bean id="outer" class="...">
<!-- instead of using a reference to a target bean, simply define the target bean inline -->
<property name="target">
<bean class="com.example.Person"> <!-- this is the inner bean -->
<property name="name" value="Fiona Apple"/>
<property name="age" value="25"/>
</bean>
</property>
</bean> - 集合类注入
<bean id="moreComplexObject" class="example.ComplexObject">
<!-- results in a setAdminEmails(java.util.Properties) call -->
<property name="adminEmails">
<props>
<prop key="administrator">administrator@example.org</prop>
<prop key="support">support@example.org</prop>
<prop key="development">development@example.org</prop>
</props>
</property>
<!-- results in a setSomeList(java.util.List) call -->
<property name="someList">
<list>
<value>a list element followed by a reference</value>
<ref bean="myDataSource" />
</list>
</property>
<!-- results in a setSomeMap(java.util.Map) call -->
<property name="someMap">
<map>
<entry key="an entry" value="just some string"/>
<entry key ="a ref" value-ref="myDataSource"/>
</map>
</property>
<!-- results in a setSomeSet(java.util.Set) call -->
<property name="someSet">
<set>
<value>just some string</value>
<ref bean="myDataSource" />
</set>
</property>
</bean> - null和空值的注入
空值<bean class="ExampleBean">
<property name="email" value=""/>
</bean>null
<bean class="ExampleBean">
<property name="email">
<null/>
</property>
</bean> - 用p-namespace可以简化对setter注入的XML配置,Spring2.0及之后的版本支持,p-namespace并不是被定义在xsd文件,而是存在于Spring的core。因此不能添加一个对应的p:schemaLocation,因为p命名空间在Spring的XSD中是没有定义的,仅仅存在于Spring Core中。换个角度想,如果指定了schemaLocation,那么就要有一个真实存在的XSD但必须引入
xmlns:p="http://www.springframework.org/schema/p
如
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean name="john-classic" class="com.example.Person">
<property name="name" value="John Doe"/>
<property name="spouse" ref="jane"/>
</bean> <bean name="john-modern"
class="com.example.Person"
p:name="John Doe"
p:spouse-ref="jane"/> <bean name="jane" class="com.example.Person">
<property name="name" value="Jane Doe"/>
</bean>
</beans>加“-ref”表示对另一个bean的引用。也可以用c-namespace简化对构造器的XML配置,但需要引如
xmlns:c="http://www.springframework.org/schema/c"
如
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="bar" class="x.y.Bar"/>
<bean id="baz" class="x.y.Baz"/> <!-- traditional declaration -->
<bean id="foo" class="x.y.Foo">
<constructor-arg ref="bar"/>
<constructor-arg ref="baz"/>
<constructor-arg value="foo@bar.com"/>
</bean> <!-- c-namespace declaration -->
<bean id="foo" class="x.y.Foo" c:bar-ref="bar" c:baz-ref="baz" c:email="foo@bar.com"/>
<!-- c-namespace index declaration -->
<bean id="foo" class="x.y.Foo" c:_0-ref="bar" c:_1-ref="baz" c:_2="foo@bar.com" />
</beans> - 复合注入
<bean id="foo" class="foo.Bar">
<property name="fred.bob.sammy" value="123" />
</bean>foo的bean有一个fred属性,fred对象有一个bob属性,bob对象有一个sammy属性。要让这个配置有效,在foo被创建之后fred、bob、sammy属性不可以为null。否则报NullPointerException异常,因此按照上面的配置最终sammy的值为123。
- depends-on
当前的bean实例化前,它depend-on的bean必须先实例化,而且可以depend-on多个bean,以空格、“,”、“;”隔开,如:<bean id="beanOne" class="ExampleBean" depends-on="manager,accountDao">
<property name="manager" ref="manager" />
</bean> <bean id="manager" class="ManagerBean" />
<bean id="accountDao" class="x.y.jdbc.JdbcAccountDao" /> - 延迟初始化bean
当ApplicationContext在startup时就会初始化已经定义的bean,这叫预初始化,但你可以通过添加lazy-init属性来设置是否预初始化,如果设置为true,只有当bean在第一次使用的时候才会初始化。<bean id="lazy" class="com.foo.ExpensiveToCreateBean" lazy-init="true"/>
- 自动装配(AutoWire)
自动装配是使用bean的autowire的属性来设置的,autowire共有4个值no(默认值)、byName、byType、constructor。其中no不自动装配,需要自己手动来装配;byName和byType都是对setter注入来说的;constructor内部也是使用byType方式来自动装配的,只是用于构造器注入。当根据byType(constructor通用)类型装配时,当在容器内找到多个匹配的类型时会抛出异常信息的。因此此时可以使用autowire-candidate="false"来设置此bean不允许被自动装配到其它bean或设置primary="true"来设置此bean作为首要被自动装配到其它bean。
Bean scopes
在Spring文档中明明列出6种开箱即用的scope,但不知道为什么却只说有5种?
6种分别如下:
- singleton:单例模式,当spring创建applicationContext容器的时候,spring会欲初始化所有的该作用域实例,加上lazy-init就可以避免预处理;只要applicationContext容器在,该实例一直存在;
- prototype:原型模式,每次通过getBean获取该bean就会新产生一个实例,创建后spring将不再对其管理;
- request:请求模式,只用于Web,每个http请求都产生一个新的实例,创建后spring将不再对其管理;
- session:会话模式,只用于Web,每个session产生一个新的实例,创建后spring将不再对其管理;
- global session:全局会话模式,只用于Web,整个session产生一个新的实例,创建后spring将不再对其管理;
- application:全局会话模式,只用于Web,每个ServletContext产生一个新的实例,创建后spring将不再对其管理;
示例
<bean id="user" class="com.byd.springdemo.User" scope="prototype">
<property name="name" value="kevin"></property>
</bean>
PS:当需要把一个http级别的scope的对象注入到其他bean中的时候,需要在声明的http级别的scope的对象中加入,如下面的userPreferences对象
<!-- an HTTP Session-scoped bean exposed as a proxy -->
<bean id="userPreferences" class="com.foo.UserPreferences" scope="session">
<!-- this next element effects the proxying of the surrounding bean -->
<aop:scoped-proxy/>
</bean> <!-- a singleton-scoped bean injected with a proxy to the above bean -->
<bean id="userService" class="com.foo.SimpleUserService">
<!-- a reference to the proxied userPreferences bean -->
<property name="userPreferences" ref="userPreferences"/>
</bean>
这样做的原因 是正常情况下singleton的userService中有一个session级别的对象,这样singleton的userService只初始化一次,而其所依赖的session级别的userPreferences也只初始化一次。这就与我们所定义的每个session对应一个对象的初衷相违背了,而使用<aop:scoped-proxy/>的时候,就会在实际调用的时候每次使用代理去代理userPreferences调用其对应的方法,代理访问的是对应的session中的对象,这样就可以实现每个session对应一个对象。而在代理的时候有两种方式,一种是基于JDK的interface的,一种是CGLIB形式的,如果要代理的类是面向对象的,就可以直接使用JDK的代理,否则就需要开启对CGLIB代理的支持,同时要引入CGLIB的jar包。
<bean id="userPreferences" class="com.foo.DefaultUserPreferences" scope="session">
<aop:scoped-proxy proxy-target-class="false"/><!-- 为true则为开启对CGLIB的支持 -->
</bean>
Scope也自己自定义的,但需要实现“org.springframework.beans.factory.config.Scope”接口,具体可参考Spring官方文档。
自定义Bean的特性
在Bean的生命周期中可以定义各种回调函数,方便来定制Bean,下面我们来一一列举。
- 初始化回调
可以通过实现org.springframework.beans.factory.InitializingBean接口来定制,InitializingBean接口只有一个方法void afterPropertiesSet() throws Exception;
但并不推荐使用InitializingBean接口,因为这种方式和Spring耦合性太强,一般采用@PostConstruct的注解或在BeanDefine的XML中使用init-method。如
<bean id="exampleInitBean" class="examples.ExampleBean" init-method="init"/>
init是Bean的自定义无参函数。
- 同上,销毁时回调也可以使用org.springframework.beans.factory.DisposableBean接口、@PreDestroy注解和XML中destroy-method来实现。Bean是单例模式,而且只有在容器关闭时才会调用destroy-method。可以使用ConfigurableApplicationContext,它扩展于ApplicationContext,它新增加了两个主要的方法:refresh()和close(),让ApplicationContext具有启动、刷新和关闭应用上下文的能力。在应用上下文关闭的情况下调用refresh()即可启动应用上下文,在已经启动的状态下,调用refresh()则清除缓存并重新装载配置信息,而调用close()则可关闭应用上下文,这些接口方法为容器的控制管理带来了便利。
PS:
- 如果初始化回调和销毁时回调在各个Bean中的方法都一样的,还可以在beans使用default-init-method和default-destroy-method统一设置,如果某个Bean没有回调,则忽略。
- 当使用注解PostConstruct和PreDestroy时,由于Spring不能默认地感知到注解,因此需要注册”CommonAnnotationBeanPostProcessor“ 或配置 “<context:annotation-config />”如
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor" /> <bean id="user" class="com.byd.springdemo.User">
<property name="name" value="kevin"></property>
</bean>
</beans>或
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd"> <context:annotation-config /> <bean id="user" class="com.byd.springdemo.User">
<property name="name" value="kevin"></property>
</bean>
</beans>注意第二种方式,必须添加
xmlns:context="http://www.springframework.org/schema/context"
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd如果同时使用注解(PostConstruct、PreDestroy)、接口(InitializingBean、DisposableBean)和XML配置的方法,他们的执行顺序是:注解、接口和XML配置。
- 还有一些其他的回调,分别实现相应的接口,如Lifecycle、LifecycleProcessor 、SmartLifecycle等。
Bean的继承
Bean可以继承父的配置,比如
<bean id="parentUser" abstract="true">
<property name="name" value="kevin"></property>
</bean> <bean id="user" class="com.byd.springdemo.User" parent="parentUser">
<property name="age" value="20"></property>
</bean>
如果父bean不使用class,则需要使用abstract来生命为抽象Bean,abstract的Bean不能实例化。
Spring容器扩展
- 通过使用BeanPostProcessor接口来定制bean
public class MyProceesor implements BeanPostProcessor { public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
System.out.println("beanName Before:"+beanName+" bean:"+bean);
return bean;
} public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
System.out.println("beanName After:"+beanName+" bean:"+bean);
return bean;
}
}然后在beans里配置bean
<bean class="net.oseye.springdemo.MyProceesor"></bean>
- 使用PropertyPlaceholderConfigurer获取property的配置
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations" value="classpath:com/foo/jdbc.properties"/>
</bean> <bean id="dataSource" destroy-method="close"
class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>jdbc.properties的配置如下
jdbc.driverClassName=org.hsqldb.jdbcDriver
jdbc.url=jdbc:hsqldb:hsql://production:9002
jdbc.username=sa
jdbc.password=root在运行时${jdbc.username}被替换成sa。
基于Java标注配置
虽然Spring提供了基于Java标注的配置,但一般不建议这样使用,因为这样造成可读性不强、代码入侵、不能部署时灵活配置等缺点。
- @Required
该标注常用于setter,用于必须提供属性,否则报“NullPointerException”异常public class User {
private String name; public String getName() {
return name;
} @Required
public void setName(String name) {
this.name = name;
}
} - @Autowired
你可以使用该标注来配置传统的setter,如public class User {
private String name; @Autowired
public void setName(String name) {
this.name = name;
} public String getName() {
return name;
}
}配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config /> <bean id="firstuser" class="net.oseye.springdemo.User"></bean> <bean class="java.lang.String">
<constructor-arg value="kevin"></constructor-arg>
</bean>
</beans>@Autowired是byType来自动注入的,如果需要byName则可以使用下文的@Resource标注。也可以使用简化版,直接在name上使用@Autowired,如
public class User {
@Autowired
private String name; public String getName() {
return name;
}
}你也可以配置构造函数
public class User {
private String name; public String getName() {
return name;
} @Autowired
public User(String name){
this.name=name;
}
}你也可以对方法进行标注配置,如
public class MovieRecommender { private MovieCatalog movieCatalog; private CustomerPreferenceDao customerPreferenceDao; @Autowired
public void prepare(MovieCatalog movieCatalog,
CustomerPreferenceDao customerPreferenceDao) {
this.movieCatalog = movieCatalog;
this.customerPreferenceDao = customerPreferenceDao;
} // ... }@Autowired有可设置的required选项,默认为true。
@Autowired默认是使用byType,但如果有多个则自动根据byName,如果没有name则报异常。但可以使用@Qualifier来配置使用哪个public class User {
@Autowired
@Qualifier("username")
private String name; public String getName() {
return name;
}
}或
public class User {
private String name; public String getName() {
return name;
} @Autowired
public void setName(@Qualifier("username")String name) {
this.name = name;
}
} - @Resource
上面@Autowired和@Qualifier的组合也可以使用@Resourcepublic class User {
private String name; public String getName() {
return name;
} @Resource(name="username")
public void setName(String name) {
this.name = name;
}
} - @PostConstruct和@PreDestroy参考前文。
- 由于不推荐使用Java标注配置,Spring文档中5.9 - 5.16不作为重点学习,因此@Service、@Repository、@Configuration、@ComponentScan、@Bean、@Component、@Scope、@Inject、@Named、@Import、@ImportResource、 @Value、@Profile、@PropertySource、@EnableLoadTimeWeaving等,如有兴趣可自行学习。
spring-framework-reference阅读笔记(一)的更多相关文章
- Spring源码阅读笔记
前言 作为一个Java开发者,工作了几年后,越发觉力有点不从心了,技术的世界实在是太过于辽阔了,接触的东西越多,越感到前所未有的恐慌. 每天捣鼓这个捣鼓那个,结果回过头来,才发现这个也不通,那个也不精 ...
- 《深入实践Spring Boot》阅读笔记之三:核心技术源代码分析
刚关注的朋友,可以回顾前两篇文章: 基础应用开发 分布式应用开发 上篇文章总结了<深入实践Spring Boot>的第二部分,本篇文章总结第三部分,也是最后一部分.这部分主要讲解核心技术的 ...
- Spring源码阅读笔记02:IOC基本概念
上篇文章中我们介绍了准备Spring源码阅读环境的两种姿势,接下来,我们就要开始探寻这个著名框架背后的原理.Spring提供的最基本最底层的功能是bean容器,这其实是对IoC思想的应用,在学习Spr ...
- Spring源码阅读笔记01:源码阅读环境准备
1. 写在前面 对于做Java开发的同学来说,Spring就像是一条绕不过去的路,但是大多数也只是停留在对Spring的简单使用层面上,对于其背后的原理所知不多也不愿深究,关于这个问题,我在平时的生活 ...
- 《深入实践Spring Boot》阅读笔记之一:基础应用开发
上上篇「1718总结与计划」中提到,18年要对部分项目拆分,进行服务化,并对代码进行重构.公司技术委员会也推荐使用spring boot,之前在各个技术网站中也了解过,它可以大大简化spring配置和 ...
- spring源码阅读笔记06:bean加载之准备创建bean
上文中我们学习了bean加载的整个过程,我们知道从spring容器中获取单例bean时会先从缓存尝试获取,如果缓存中不存在已经加载的单例bean就需要从头开始bean的创建,而bean的创建过程是非常 ...
- Spring Framework Reference,Documentation,spring英文文档.pdf 官方文档
直接上链接:http://files.cnblogs.com/files/kongkaikai/spring-framework-reference.pdf 官网链接:http://docs.spri ...
- 《深入实践Spring Boot》阅读笔记之二:分布式应用开发
上篇文章总结了<深入实践Spring Boot>的第一部分,这篇文章介绍第二部分:分布式应用开发,以及怎么构建一个高性能的服务平台. 主要从以下几个方面总结: Spring Boot SS ...
- Spring技术内幕阅读笔记(一)
1.BeanFactory:实现ioc容器的最基本形式.String FACTORY_BEAN_PREFIX = "&";Object getBean(String var ...
- Spring源码阅读笔记03:xml配置读取
前面的文章介绍了IOC的概念,Spring提供的bean容器即是对这一思想的具体实现,在接下来的几篇文章会侧重于探究这一bean容器是如何实现的.在此之前,先用一段话概括一下bean容器的基本工作原理 ...
随机推荐
- gdb命令整理
Microsoft Windows XP [版本 ] (C) 版权所有 - Microsoft Corp. C:\Documents and Settings\Administrator>e: ...
- XML文档的PHP程序查询代码
PHP文档: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" " http://www ...
- thinkPHP 模板中的语法
一.导入CSS和JS文件 1.css link js scr <link rel='stylesheet' type='text/css' href='__PUB ...
- 学习笔记: JavaScript/JQuery 的cookie操作
转自:http://blog.csdn.net/barryhappy/archive/2011/04/27/6367994.aspx cookie是网页存储到用户硬盘上的一小段信息.最常见的作用是判断 ...
- CSS继承性和层叠性
一. 继承性 1. 含义:从自己开始直到所包裹的最小的元素,都可以继承一些特有的属性. 2. 作用范围: a. color.text-开头的.line-开头的.font-开头的,均可以继 ...
- 采用FirePHP调试PHP程序
采用FirePHP调试PHP程序 FirePHP是什么? FirePHP是一个利用Firebug console栏输出调试信息方便程序调试.这一切只需要调用几个简单的函数. 他看起来是怎么个样子? 1 ...
- jQuery 判断checkbox是否被选中 4种方法
下午写JS验证,有一个需求需要判断 checkbox是否被选择,查阅相关资料后,总结以下4种方法,分享给大家. <!DOCTYPE html> <html lang="en ...
- 微信小程序开发系列(二)小程序的全局文件
其实你已经知道了小程序的文件结构 上一节讲到,小程序的页面由三部分组成: 视图(.wxml).逻辑(.js).样式(.wxss). 我们这次重新展开文件结构: 小程序用到的文件类型只有四种,正如你所看 ...
- Redis系列四(keepalived+lvs搭建负载均衡)
1.安装Keepalived(主备服务器都要安装) 10.8.80.218 主服务器 10.8.80.217 备服务器 10.8.80.200 虚拟IP $ wget http://www.ke ...
- 从零开始学习C#——HelloWorld(一)
从零开始学习C# 老规矩Hello World 您的第一个程序 visual studio 如何使用就不说了 //编程的开始,Hello World! program in C# using Syst ...