您的位置:首页 > 编程语言 > Java开发

spring-framework-reference阅读笔记(一)

2014-12-07 15:14 190 查看
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更规范化了。

依赖注入(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的组合也可以使用@Resource

public 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等,如有兴趣可自行学习。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: