Spring Framework Runtimehtml
首先須要對Spring FrameWok框架有個直觀的認識java
Java日誌框架的發展史spring
在讀到Spring依賴JCL的時候,對Java的日誌系統作點普及!sql
最 早出現的日誌框架是apache提供的log4j,使用最爲普遍,成爲了Java日誌的事實上的標準;然而當時Sun公司在jdk1.4中增長了 JUL(java.util.logging),企圖對抗log4j,因而形成了混亂,固然此時也有其它的一些日誌框架的出現,如simplelog等, 簡直是亂上加亂。apache
解決這種混亂的方案出現了:抽象出一個接口層:因而開源社區提供了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時綁定的。session
Spring中如何使用日誌系統 app
<dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.14</version> </dependency>
<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>
<dependency> <groupId>org.slf4j</groupId> <artifactId>jcl-over-slf4j</artifactId> <version>1.5.8</version> </dependency>
<dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.7</version> </dependency>
Spring資源 框架
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; }
public interface ResourceLoader { Resource getResource(String location); }
Resource template = ctx.getResource("some/resource/path/myTemplate.txt");
Resource template = ctx.getResource("classpath:some/resource/path/myTemplate.txt");
這 裏咱們先挑一個DefaultResourceLoader來說。DefaultResourceLoader在獲取Resource時採用的是這樣的策 略:首先判斷指定的location是否含有「classpath:」前綴,若是有則把location去掉「classpath:」前綴返回對應的 ClassPathResource;不然就把它當作一個URL來處理,封裝成一個UrlResource進行返回;若是當成URL處理也失敗的話就把 location對應的資源當成是一個ClassPathResource進行返回。classpath:com/myapp/config.xml
file:///data/config.xml
http://myserver/logo.png
ResourceLoader resourceLoader=new DefaultResourceLoader(); Resource resource=resourceLoader.getResource("/a.xml"); System.out.println(resource.exists());
ApplicationContext ctx = new FileSystemXmlApplicationContext("classpath:conf/appContext.xml");
PS:classpath*是加載多個資源,並且可使用通配符。
Spring IOC
<beans> <import resource="services.xml"/> <import resource="resources/messageSource.xml"/> <import resource="/resources/themeSource.xml"/> <bean id="bean1" class="..."/> <bean id="bean2" class="..."/> </beans>
<alias name="fromName" alias="toName"/>
<bean id="exampleBean" class="examples.ExampleBean"/> <bean name="anotherExample" class="examples.ExampleBeanTwo"/>
<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; } }
<!-- 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; } }
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>
package examples; public class ExampleBean { // Fields omitted @ConstructorProperties({"years", "ultimateAnswer"}) public ExampleBean(int years, String ultimateAnswer) { this.years = years; this.ultimateAnswer = ultimateAnswer; } }
<bean id="exampleBean" class="examples.ExampleBean"> <constructor-arg value="7500000"/> <constructor-arg value="42"/> </bean>
<bean id="exampleBean" class="examples.ExampleBean"> <constructor-arg type="int" value="7500000"/> <constructor-arg type="java.lang.String" value="42"/> </bean>
<bean id="exampleBean" class="examples.ExampleBean"> <constructor-arg index="0" value="7500000"/> <constructor-arg index="1" value="42"/> </bean>
<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"/>
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"/>
<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>
<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>
<bean class="ExampleBean"> <property name="email" value=""/> </bean>
<bean class="ExampleBean"> <property name="email"> <null/> </property> </bean>
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>
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>
<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 id="lazy" class="com.foo.ExpensiveToCreateBean" lazy-init="true"/>
Bean scopes
在Spring文檔中明明列出6種開箱即用的scope,但不知道爲何卻只說有5種?
6種分別以下:
示例
<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,下面咱們來一一列舉。
void afterPropertiesSet() throws Exception;
<bean id="exampleInitBean" class="examples.ExampleBean" init-method="init"/>
PS:
<?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
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容器擴展
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; } }
<bean class="net.oseye.springdemo.MyProceesor"></bean>
<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.driverClassName=org.hsqldb.jdbcDriver jdbc.url=jdbc:hsqldb:hsql://production:9002 jdbc.username=sa jdbc.password=root
基於Java標註配置
雖然Spring提供了基於Java標註的配置,但通常不建議這樣使用,由於這樣形成可讀性不強、代碼入侵、不能部署時靈活配置等缺點。
public class User { private String name; public String getName() { return name; } @Required public void setName(String name) { this.name = name; } }
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>
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; } // ... }
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; } }
public class User { private String name; public String getName() { return name; } @Resource(name="username") public void setName(String name) { this.name = name; } }