一:Spring並天下
1:Spring帝國:
①:Spring崛起
什麼是Spring:
源於Rod Johnson在其著作《Expert one on one J2EE design and development》中闡述的部分
理念和原型的衍生而來.Spring是一個輕量級的DI/AOP容器的開源框架,致力於構建輕量級的JavaEE應用,簡化應用
開發,本身涵蓋了傳統應用開發還拓展到移動端,大數據領域.
什麼是容器(Container):
從程序設計角度看就是裝對象的對象,因爲存在放入,拿出等操作,所以容器還是要管理對象的生命週期,如
Tomcat就是Service和JSP的容器.
Spring提供了JavaEE每一層的解決方案(full stack) .Spring其實就是全棧式框架.
![Spring與SpringMVC的框架整合](https://img-blog.csdn.net/20180404200433463?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MDE2MTcwOA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
②:Spring的優勢:
Spring除了不能幫我們寫業務邏輯,其餘的幾乎什麼都能幫助我們簡化開發.
①:Spring能幫我們低侵入/低耦合地根據配置文件創建及相關對象之間的依賴關係.
②:Spring面向切面編程能幫我們無耦合的實現日誌記錄,性能統計,安全控制等.
③:Spring能非常簡單的且強大的聲明式事務管理.
④:Spring提供了與第三方數據訪問框架(如:Hibemate,JPA)無縫集成,且自己也提供了一套JDBC模板來方便數據庫訪問.
⑤:Spring提供與第三方Web(如Struts1/2,JSF)框架無縫集成,且自己也提供了一套Spring MVC框架來方便Web層搭建.
⑥:Spring能方便的與Java Mail,任務調度,緩存框架等技術整合,降低開發難度.
③:Spring帝國
Spring主要產品:
Spring FrameWork:
Spring帝國之核心,其他Spring其他產品都是基於Spring框架而來.
Spring Boot:
Spring Boot 是由Pivotal團隊提供的全新框架,其設計目的是用來簡化新Spring應用
的初始搭建以及開發過程.該框架使用了特定的方式來進行配置,從而是開發人員不在需要定義樣板化的配置.
Spring Cloud:Spring cloud微服務框架,爲開發者提供了在分佈式系統(配置管理,服務發現,熔斷,路由,微代理,
控制總線,一次性token,全居鎖,leader選舉,分佈式session,集羣狀態)中快速構建的工具,使用Spring Cloud的
開發者可以快速的啓動服務或構建應用,同時能夠快速和雲平臺資源進行對接.
Spring Cloud Data Flow:
Spring Cloud Data Flow簡化了專注於數據流處理的應用程序的開發和部署.通過
SpringBoot啓動應用,採用Spring Cloud Stream,Spring Cloud Task完成微服務構建.
官網的推薦組合:Spring Boot + Spring Cloud + Spring Cloud Data Flow
![Spring的其他主要項目版圖](https://img-blog.csdn.net/20180404203728808?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MDE2MTcwOA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
④:Spring基石
![Spring基石,瞭解一下就行,框住的是我們需要學習的](https://img-blog.csdn.net/20180404204632103?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MDE2MTcwOA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
⑤:Spring框架包
Spring框架包包含兩大部分:
1:spring-framework-5.X.RELEASE:Spring核心組件(必須).
docs: Spring開發,幫助文檔.
libs: Spring 核心組件的,jar包,源代碼,文檔.
schema: Spring配置文件的schema約束文件.
2:spring-framework-3.0.5.RELEASE-dependencies:
Spring依賴的第三方組件(根據需要拷貝),包含了各大開源組織提供的依賴jar,比如日誌庫,AOP聯盟庫,連接池庫等.
建議使用meve來下載jar包,不需要拷貝jar包了.
⑥:STS工具
Eclipse: STS工具 Spring Tool Suite基於Eclipse的開發工具.
IDEA: 後面會錄製一套IDEA的視頻.
2:Spring基礎
①:Ioc和DI思想
IoC: Inversion of Control(控制反轉):讀作"翻轉控制",更好理解,不是什麼技術,而是一種設計思想,
好比於MVC.就是將原本在程序中手動創建對象的控制權,交由Spring框架來管理.
正控:若調用者需要使用某個對象,其自身就得負責該對象及該對象所依賴對象的創建和組裝.
反控:調用者只管負責從Spring容器中獲取需要使用的對象,不關心對象的創建過程,也不關心該對象依賴對象的
創建以及依賴關係的組裝,也就是把創建對象的控制權翻轉給了Spring框架.
DI: Dependency Injection (依賴注入)從字面上分析: IoC:指將對象的創建權,翻轉給了Spring容器: DI:指Spring
創建對象的過程中,將對象依賴屬性(常量,對象,集合)通過配置設置值給該對象.
IoC 從字面意義上很難體現出誰來維護對象之間的關係,Martin Fowler提出一個新的概念--DI,更明確描述了"被注入對象(service對象)
依賴IoC容器來配置依賴對象(DAO對象)".
②:HelloWord程序
依賴jar:
spring-beans-版本.RELEASE.jar
spring-core-版本.RELEASE.jar
報錯再添加:
com.springsource.org.apache.commons.logging-1版本.jar
開發jar包
1:準備jar包
2:開發HelloWorld程序
3:在applicationContext.xml中完成配置(如何獲取xsd聲明)
4:啓動Spring容器
5:從容器中獲取指定名稱的bean
6:調用bean的方法
什麼是BeanFactory:
BeanFactory是Spring最古老的接口,表示Spring IoC容器--生產bean對象的工廠,負責配置,創建和管理bean
什麼是Bean: 被Spring Ioc容器管理的對象稱之爲bean.
Spring Ioc容器如何知道哪些是它管理的對象:
此時需要配置文件:Spring Ioc容器通過讀取配置文件中的配置元數據,通過元數據對應用中的各個對象進行實例化及裝配.
元數據的配置有三種方式(後講):
1:XML-based configuration
2:Annotation-based configuration
3:Java-bean configuration
Spring IoC管理bean的原理:
1:通過Resource對象加載配置文件
2:解析配置文件,得到指定名稱的bean
3:解析bean元素,id作爲bean的名字,class用於反射得到bean實例:
注意:此時,bean類必須存在一個無參數構造器(和訪問權限無關);
4:調用getBean方法的時候,從容器中返回對象實例;
結論:就是把代碼從JAVA文件中轉移到XML中.
③:getBean方法的三種簽名
//使用Spring框架之後
@Test
public void test2() throws Exception {
HelloWorld world = null;
//---------------------------------
//1:從classpath路徑去尋找資源問價,創建資源對象
Resource resource = new ClassPathResource("applicationContext.xml");
//2:根據資源對象,創建Spring IoC容器對象
BeanFactory factory = new XmlBeanFactory(resource);
//3:從Spring IoC容器中獲取指定名稱(helllo world)對象
//簽名一:Object getBean(String beanName);//根據bean對象在容器中的名稱來取
//world = (HelloWorld) factory.getBean("HelloWorld");
//簽名二:<T> T getBean(Class<T> requiredType)//按照指定的類型去尋找bean對象
//world = factory.getBean(HelloWorld.class);
//簽名三:<T> T getBean(String name, @Nullable Class<T> requiredType)根據bean的類型+ID名稱去尋找,推薦的
world = factory.getBean("HelloWorld",HelloWorld.class);
//---------------------------------
world.sayHello();
}
④:Eclipse提示XML語法
XML需要導入schema約束,約束指向網絡路徑:
方式一:連網後,自動緩存路徑文件到本地,提供提示功能;
方式二:無連網,需要配置xsd schema文件位置(操作如下圖);
①:到解壓spring/schemas/beans/spring-bean.xsd.
②:選擇schema location方式.
③:複製網絡路徑 http://www.springframework.org/schema/beans/spring-beans.xsd
⑤:Spring基本配置
<bean id="helloWorld" class="cn.wolfcode.hello.HelloWorld"/>
name跟id 以後只需要用id屬性就行,表示的意思一樣,但是name元素可以用空格隔開不同的名字
<import resource=""/>元素
在開發中,隨着應用規模的增加,系統中<bean>元素配置的數量也會增加,導致applicationContext.xml配置
文件變得非常臃腫,爲了提高其可讀性,我們可以將一個applicationContext.xml文件分解成多個配置文件,
然後在applicationContext.xml文件中包含其他配置文件即可.
語法如下: <import resource="classpath:cn/wolfcode/hello/hello.xml"/>
使用import元素注意:
1:默認情況下:從classpath的根路徑尋找.
2:可以使用前綴來定位文件的基礎位置:
①:[classpath:] 後面的文件從classpath路徑開始找(推薦);
②:[file]:後面的文件使用文件系統的路徑開始找;
注意:只有當框架中實現了Resource接口才能夠識別上訴的前綴標識符.
⑥:Spring測試框架
測試依賴:
Spring-test-版本.RELEASE.jar
Spring-context-版本.RELEASE.jar
Spring-aop-版本.RELEASE.jar
Spring-expression-版本.RELEASE.jar
//使用Junit4的測試案例
//運行Spring的jUnit4
@RunWith(SpringJUnit4ClassRunner.class)
//上下文配置對象,尋找配置文件的
//@ContextConfiguration("classpath:cn/wolfcode/spring_test/springtext.xml")
@ContextConfiguration//默認從測試了路徑找 測試類名-context.xml文件
public class SpringTestTest {
//表示自動按照類型從Spring容器中找到bean對象,並設置給該字段
@Autowired
private SomeBean bean;
@Test
public void test() throws Exception {
bean.doWork();
}
}
//使用Junit5方式的測試
@SpringJUnitConfig
public class SpringTestTest{
@Autowired
private SomeBean bean;
@Test
void testName(){
bean.doWork();
}
}
二: 帝國之劍 IoC
1:IoC
①:IOC容器
1:SpringIoC容器(Contaner):
BeanFactory: Spring 最底層的接口,只提供了IoC功能,負責創建,組裝,管理Bean,在應用中,一般不使
用BeanFactory,而推薦使用ApplicationContext(應用上下文).
ApplicationContext:接口繼承了BeanFactory,除此之外還提供AOP集成,國際化處理,事件傳播,統一資源加載等功能.
2:Bean的創建時機(此時不使用Spring Test):
①:BeanFactory需要等到獲取某一個bean的時候纔會創建bean--延遲初始化.
②:ApplicationContext在啓動Spring容器的時候就會創建所有的bean(Web應用建議).
bean屬性中的lazy-init="true"也可以延遲初始化,也可以設置到到schema上面的default-lazy-init="true"
/**
結論:BeanFactory有延遲初始化的特點,在創建Spring容器的時候,不會立馬去創建容器中管理的Bean對象
而是要等到從容器中去獲取對象的時候,纔去創建對象.
*/
//使用BeanFactory
@Test
public void testBeanFactory() throws Exception {
Resource resource = new ClassPathResource("cn/wolfcode/container/ContainerTest-Context.xml");
BeanFactory factory = new XmlBeanFactory(resource);
System.out.println("====================");
Person person = factory.getBean("person",Person.class);
System.out.println(person);
}
/**
結論:在創建Spring容器的時候,就會把容器中管理的bean馬上初始化,而不會等到獲取bean的時候纔去初始化.
*/
//使用ApplicationContext
@Test
public void test2() throws Exception {
ApplicationContext ctx = new ClassPathXmlApplicationContext("cn/wolfcode/container/ContainerTest-Context.xml");
System.out.println("============================");
Person person = ctx.getBean("person",Person.class);
System.out.println(person);
}
②:bean實例化方式:
①:構造器實例化(無參數構造器),最標準,使用最多. (使用比較多)
②:靜態工廠方法實例化:解決系統遺留問題
③:實例工廠方法實例化:解決系統遺留問題
④:實現FactoyrBean接口實例化:實例工廠變種,如集成MyBatis框架使用: (使用比較多)
org.mybatis.spring.SqlSessionFactoryBean
<!-- ①:構造器實例化(無參數構造器),最標準,使用最多 -->
<bean id="cat1" class="cn.wolfcode.createbean._01_constructor.Cat1"/>
<!-- ②:靜態工廠方法實例化:解決系統遺留問題 -->
<bean id="cat2" class="cn.wolfcode.createbean._02_static_factory.Cat2Factory"
factory-method="createInstance"/>
<!-- ③:實例工廠方法實例化:解決系統遺留問題 -->
<bean id="cat3" class="cn.wolfcode.createbean._03_instance_factory.Cat3Factory"/>
<bean id="getcat3" factory-bean="cat3" factory-method="createInstance"/>
<!-- ④:實現FactoryBean接口實例化:實例工廠變種,如集成MyBatis框架使用 -->
<bean id="dat4" class="cn.wolfcode.createbean._04_factory_bean.Cat4Factory">
<property name="username" value="你好"></property>
</bean>
③:bean的作用域:
在Spring容器中是指其創建的Bean對象相對於其他Bean對象的請求可見範圍
<bean id="" scope="作用域"/>
singleton: 單例,在Spring IoC容器中僅存在一個Bean實例 (默認的scope)
proptotype: 多例,每次從容器中調用Bean時,都返回一個新的實例,即每次調用getBean()時,相當於執行new XxxBean();不會再容器啓動時創建對象
request: 用於web開發,將Bean放入request範圍,request.setAttribute("xxx")在調用一個request獲得同一個Bean
session:用於web開發,將Bean放入Session範圍,在同一個 Session獲得同一個Bean
globalSession:一般用於Porlet應用環境,分佈式系統存在全局session概念(單點登錄),如果不是porlet環境.
globalSession 等同於Session
Spring5開始出現:websocket, globalSession作廢.
在開發中主要使用 scope="singleton" scope="prototype"
總結: 對於Struts1中的Action使用request, Struts2中的Action使用prototype類型,其他使用singleton
④:bean初始化和銷燬
init-method: 定義初始化方法,在構造器執行之後,立馬執行
destroy-method: 定義銷燬之前的方法,在銷燬執行之前,調用
scope: 設置爲"prototype" 不是 單例設計模式, 他不知道你啥時候調用完,所以就不關閉資源 考慮資源來之不易,不易輕易釋放
<bean id="ds" class="cn.wolfcode.lifecycle.MyDataSource" scope="singleton"
init-method="open" destroy-method="close"/>
此方法在Spring測試類可用
如果使用ApplicationContext來創建對象,就得手動關閉資源
@Test
public void testName1() throws Exception {
@Cleanup
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("cn/wolfcode/lifecycle/App-Context.xml");
MyDataSource ds = ctx.getBean("ds",MyDataSource.class);
ds.doWork();
}
三種關閉資源方法:最後加 ds.close(); @Clearup; ctx.registerShutdownHook();
⑤:bean的實例化過程(生命週期)
bean的生命週期: bean從出身--消亡直接的整個過程
BeanFactory: 延遲初始化特點
ApplicationContext: 在啓動Spring容器的時候,就會去創建bean對象
![bean的生命週期](https://img-blog.csdn.net/2018040512541723?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MDE2MTcwOA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
![bean的生命週期2](https://img-blog.csdn.net/20180405125513373?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MDE2MTcwOA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
![bean的生命週期3](https://img-blog.csdn.net/20180405132714642?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MDE2MTcwOA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
2: DI
①:通過XML配置裝配
DI:Dependency Injection(依賴注入)
從字面上分析:IoC:指對象的創建權,反轉給了Spring容器;
DI:指Spring創建對象的過程中,將對象依賴屬性(常量,對象,集合)通過配置設值給該對象.
什麼是注入操作? setter方法 構造器
注入值的類型:
1):常量值(簡單類型):value元素
2):對象 : ref元素
3):集合 : 對應集合類型元素
通過XML配置裝配(不推薦)
<bean id="dog" class="" autowire="byType" /> autowire: byName byType constructor no
②:setter注入
注入常量 注入對象 注入集合 跟上面注入方法一樣
<!-- 屬性注入:常量類型 -->
<bean id="employee" class="cn.wolfcode.di_setter.Employee1">
<property name="name" value="will"></property>
<property name="age" value="17"></property>
<property name="salary" value="5000"></property>
</bean>
<!-- 下面這種方法不推薦 -->
<!-- <bean id="employee" class="cn.wolfcode.di_setter.Employee1" p:name="Lucy" p:age="18" p:salary="1000"/> -->
<!-- 屬性注入:對象類型 -->
<bean id="cat1" class="cn.wolfcode.di_setter.Cat1"></bean>
<bean id="person" class="cn.wolfcode.di_setter.Person1" >
<property name="c1" ref="cat1"></property>
</bean>
<!-- 屬性注入:集合類型 -->
<bean id="collectionBean1" class="cn.wolfcode.di_setter.CollectionBean1">
<property name="set">
<set>
<value>set1</value>
<value>set2</value>
</set>
</property>
<property name="list">
<list>
<value>list1</value>
<value>list2</value>
</list>
</property>
<property name="array">
<array>
<value>array1</value>
<value>array2</value>
</array>
</property>
<property name="map">
<map>
<entry key="key1" value="value1"/>
<entry key="key2" value="value2"/>
</map>
</property>
<!-- <property name="prop">
<props>
<prop key="p1">v1</prop>
<prop key="p2">v2</prop>
</props>
</property> -->
<property name="prop">
<value>
p1=v1
p2=v2
p3=v3
</value>
</property>
</bean>
③:構造器注入
把上面的property換成constructor-arg 即可
<bean id="person2" class="cn.wolfcode.di_constructor.Person2" >
<constructor-arg name="c2">
<bean class="cn.wolfcode.di_constructor.Cat2"/>
</constructor-arg>
</bean>
④:bean元素的繼承
多個bean元素共同配置的抽取,實則是bean配置的拷貝,和Java的繼承不同.
<!-- 多個bean共同配置的抽取 -->
<bean id="base" abstract="true">
<property name="name" value="will"></property>
<property name="age" value="19"></property>
</bean>
<!-- 配置SomeBase1 -->
<bean id="someBean1" class="cn.wolfcode.bean_tag_inheritance.SomeBean1" parent="base">
<property name="weight" value="500"></property>
</bean>
<!-- 配置SomeBase2 -->
<bean id="someBean2" class="cn.wolfcode.bean_tag_inheritance.SomeBean2" parent="base">
<property name="age" value="99"></property>
<property name="color" value="業樓"></property>
</bean>
⑤:配置數據庫連接池
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class App {
@Autowired
private DataSource ds;
@Test
public void testName() throws Exception {
/*ds = new DruidDataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3306/springdemo");
ds.setUsername("root");
ds.setPassword("111111");
ds.setInitialSize(2);*/
@Cleanup
Connection conn = ds.getConnection();
@Cleanup
PreparedStatement ps = conn.prepareStatement("SELECT * FROM student");
@Cleanup
ResultSet rs = ps.executeQuery();
while(rs.next()){
System.out.print(rs.getLong("id")+",");
System.out.print(rs.getString("name")+",");
System.out.println(rs.getInt("age")+",");
}
}
}
⑥:property-placeholder
<!--
先配置schema屬性
然後就可以使用context:property-placeholder標籤了
從classpath:db.properties文件中去加載資源
system-properties-mode="NEVER"表示不從系統中找屬性,因爲系統中有個也叫
username的屬性名稱,跟JDBC連接池的屬性名稱相同,有衝突
最好在properties文件中屬性前面加個JDBC.
-->
<!-- 從classpath的跟路徑去加載db.properties文件 -->
<context:property-placeholder location="classpath:db.properties" system-properties-mode="NEVER"/>
<!-- 配置一個druid的連接池 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
init-method="init" destroy-method="close" >
<property name="driverClassName" value="${jdbc.driverClassName}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
<property name="initialSize" value="${jdbc.initialSize}"></property>
</bean>
⑦:模擬用戶註冊的例子
查看我的Eclipse代碼,利用xml配置的方式回顧了IoC跟DI.
domain
@Setter@ToString@Getter
public class User {
private Long id;
private String name;
private int age;
}
dao
public interface IUserDAO {
void save(User u);
}
impl
public class IUserDAOImpl implements IUserDAO{
@Setter
private DataSource ds;
@SneakyThrows
public void save(User u){
System.out.println("保存操作");
@Cleanup
Connection conn = ds.getConnection();
String sql = "INSERT INTO user (name,age) values (?,?)";
@Cleanup
PreparedStatement ps = conn.prepareStatement(sql);
ps.setString(1,u.getName());
ps.setInt(2, u.getAge());
ps.executeUpdate();
}
}
service
public interface IUserService {
void register(User user);
}
impl
public class UserServiceImpl implements IUserService{
private IUserDAO dao;
public void setDao(IUserDAO dao) {
this.dao = dao;
}
@SneakyThrows
public void register(User user){
System.out.println("註冊操作");
dao.save(user);
}
}
action
//模擬Struts2的Action/SpringMVC的Controller
public class UserAction {
@Setter
private IUserService service;
public String execute() throws Exception{
System.out.println("註冊請求");
service.register(new User());
return "success";
}
}
app
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class App {
@Autowired
private UserAction userAction;
@Test
public void testRegister() throws Exception {
userAction.execute();
}
}
app-Context.xml
<!-- 從classpath的跟路徑去加載db.properties文件 -->
<context:property-placeholder location="classpath:db.properties" system-properties-mode="NEVER"/>
<!-- 配置一個druid的連接池 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
init-method="init" destroy-method="close">
<property name="driverClassName" value="${jdbc.driverClassName}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
<property name="initialSize" value="${jdbc.initialSize}"></property>
</bean>
<!-- 配置DAO -->
<bean id="userdao" class="cn.wolfcode.register.dao.impl.IUserDAOImpl">
<property name="ds" ref="dataSource"></property>
</bean>
<!-- 配置Service -->
<bean id="UserService" class="cn.wolfcode.register.service.impl.UserServiceImpl">
<property name="dao" ref="userdao"></property>
</bean>
<!-- 配置
如果使用Struts2的Action:此時bean的作用域應該是多例: scope="prototype"
如果使用SpringMVC的Controller: 此時bean的作用域依然還是使用單例:singleton /或者不寫
-->
<bean id="userAction" class="cn.wolfcode.register.action.UserAction" scope="prototype">
<property name="service" ref="UserService" ></property>
</bean>
3:使用註解配置
①:DI註解
Autowired和Qualifier註解
Spring規範提供
1:可以讓Spring自動的把屬性的對象找出來,並注入到對象.
2:可以貼在字段或者setter方法上面
3:可以同時注入多個對象
@Autowired
public void setter(OtherBean otherBean,OtherBean other2){}
4:可以注入一些Spring內置的重要對象,比如BeanFactory,ApplicationContext,ServiceContext等;
5:默認情況下Autiwrired註解必須要能找到對應的對象,否則報錯.
通過required=false來避免這個問題:@Autowired(required=false)
6:第三方程序:Spring3.0之前,需要手動配置Autowired註解的解析程序:
<context:annotation-config/>在Web開發中必須配置
7:Autowired註解尋找bean的方法:
1):首先按照依賴對象的類型找,如果找到,就是用setter或者字段直接注入
2):如果Spring上下文中找到多個匹配類型,再按照名字去找,如果沒有 匹配報錯;
3):可以通過使用@Qualifier("name")標籤來規定依賴對象按照bean的id和類型的組合方式去找;
Resource
DI註解:
Spring官方: Autowired
JavaEE規範: Resource
共同點: 都需要配置DI註解解析器: <context:annotation-config/>
不同點: Resource註解必須要能找到對應的對象,否則報錯.
Resource註解首先按照名字去找,如果找到,就使用setter或者字段注入;
如果按照名字找不到,再按照類型去找,但如果找到多個匹配類型,報錯;
Resource可以直接使用name屬性指定bean的名稱(@Resource(name="名字"));但是
如果指定的name,就只能按照name去找如果找不到,就不再按照類型去找
Value
注入:
常量類型: value Value
對象類型: ref Autowired/Resource
@Value("${service.port}")
private int port;
<!--需要加載的配置文件用 逗號 隔開-->
<context:property-placeholder location="classpath:db.properties,classpath:server.properties"/>
②:IoC註解
Component註解和其stereotype註解
//註解配置:@Component
@Component("myDataSource")//組件如果不寫value屬性值,此時bean的id默認是類型首字母小寫;
public class MyDataSource {
}
<!-- IoC註解解析器 -->
<context:component-scan base-package="cn.wolfcode.ioc"/>
bean組件版型:四個組件的功能是相同的,只是用於標註不同類型的組件.
@Component泛指組件,當組件不好歸類的時候,我們可以使用這個註解進行標註.
@Repository用於標註數據訪問組件,即DAO組件.
@Service用於標註業務層組件.
@Controller用於標註控制層組件(如struts中的Ation,SpringMVC的Controller).
他們幾個的功能跟component功能其實是一模一樣的.優先使用下面3種註解,當不屬於其他組件再使用component
③:Scope 和 PostConstruc 以及 PreDestroy 註解
@PostConstruct用於貼在初始化方法上
@PreDestroy用於貼在銷燬方法上
@Component
@Scope("singleton")
public class SomeBean {
public SomeBean(){
System.out.println("構建SomeBean對象");
}
@PostConstruct//構建對象之後
public void open(){
System.out.println("初始化方法");
}
@PreDestroy//銷燬之前
public void close(){
System.out.println("銷燬前掃尾方法");
}
public void doWork(){
System.out.println("工作");
}
}
之後記得寫IoC註解解析器
<context:component-scan base-package="cn.wolfcode.lifecycle"/>
④:使用註解完成註冊案例
注意:
使用註解並不能完全取代XML的配置
比如配置連接池DruiDataSource,我們就不能到這個類中去貼註解.
JavaConfig + 註解
@setter註解貼在字段上面僅僅是爲我們生成一個Setter方法,本身不能完成注入操作.
@Autowired註解貼在字段上面,自動從Spring 容器中去找到匹配的對象,並設置給該字段.
IoC和DI其實是一個東西:
IoC:字面上,更多強調的是Spring幫我們創建對象.
DI:字面上,Spring不僅幫我們創建對象,還要爲該對象設置依賴的數據.
最後學會用XML與註解完成註冊案例配置
domain
@Setter@ToString@Getter
public class User {
private Long id;
private String name;
private int age;
}
dao
public interface IUserDAO {
void save(User u);
}
impl
@Repository
public class IUserDAOImpl implements IUserDAO{
@Autowired
private DataSource ds;
@SneakyThrows
public void save(User u){
System.out.println("保存操作");
@Cleanup
Connection conn = ds.getConnection();
String sql = "INSERT INTO user (name,age) values (?,?)";
@Cleanup
PreparedStatement ps = conn.prepareStatement(sql);
ps.setString(1,u.getName());
ps.setInt(2, u.getAge());
ps.executeUpdate();
}
}
service
public interface IUserService {
void register(User user);
}
impl
@Service
public class UserServiceImpl implements IUserService{
@Autowired
private IUserDAO dao;
@SneakyThrows
public void register(User user) {
System.out.println("註冊操作");
dao.save(user);
}
}
action
@Component//變現層
public class UserAction {
@Autowired
private IUserService service;
public String execute() throws Exception{
System.out.println("註冊請求");
service.register(new User());
return "success";
}
}
APP
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class App {
@Autowired
private UserAction userAction;
@Test
public void testRegister() throws Exception {
userAction.execute();
}
}
APP-context.xml
<?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
" >
<!-- DI註解解析器 -->
<context:annotation-config/>
<!-- IoC註解解析器 -->
<context:component-scan base-package="cn.wolfcode"/>
<!-- 從classpath的跟路徑去加載db.properties文件 -->
<context:property-placeholder location="classpath:db.properties" system-properties-mode="NEVER"/>
<!-- 配置一個druid的連接池 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
init-method="init" destroy-method="close">
<property name="driverClassName" value="${jdbc.driverClassName}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
<property name="initialSize" value="${jdbc.initialSize}"></property>
</bean>
</beans>