Spring框架—控制反轉(IOC)
1 Spring框架概述
1.1 什麼是Spring
1.2 Spring的優勢
1.3 Spring的體系結構
2 入門案例:(IoC)
2.1導入jar包
2.2目標類
2.3 配置文件
2.4測試
3 入門案例:DI
3.1 目標類
3.2 dao
3.3 service
3.4 配置文件
3.5 測試
4 依賴注入裝配Bean 基於xml
4.1屬性依賴注入
4.1.1 構造方法
4.1.2 setter方法
4.2 集合依賴注入
5 依賴注入裝配Bean 基於註解
Spring框架—面向切面編程(AOP)
1 什麼是AOP
2 AOP實現原理
3 AOP術語【掌握】
4 AOP實現方式
4.1手動方式
4.1.1JDK動態代理
4.1.2 CGLIB字節碼加強
4.2半自動
4.2.1目標類
4.2.2切面類
4.2.3Spring 配置
4.2.4 測試
4.3全自動
4.3.1 Spring配置
4.3.2 測試
Spring框架—控制反轉(IOC)
1 Spring框架概述
1.1 什麼是Spring
Spring是一個開源框架,Spring是於2003 年興起的一個輕量級的Java 開發框架,由Rod Johnson 在其著做Expert One-On-One J2EE Development and Design中闡述的部分理念和原型衍生而來。它是爲了解決企業應用開發的複雜性而建立的。框架的主要優點之一就是其分層架構,分層架構容許使用者選擇使用哪個組件,同時爲 J2EE 應用程序開發提供集成的框架。Spring使用基本的JavaBean來完成之前只可能由EJB完成的事情。然而,Spring的用途不只限於服務器端的開發。從簡單性、可測試性和鬆耦合的角度而言,任何Java應用均可以從Spring中受益。Spring的核心是控制反轉(IoC)和麪向切面(AOP)。簡單來講,Spring是一個分層的JavaSE/EE full-stack(一站式) 輕量級開源框架。
1.2 Spring的優勢
方便解耦,簡化開發 (高內聚低耦合)
Spring就是一個大工廠(容器),能夠將全部對象建立和依賴關係維護,交給Spring管理
spring工廠是用於生成bean
AOP編程的支持
Spring提供面向切面編程,能夠方便的實現對程序進行權限攔截、運行監控等功能
聲明式事務的支持
只須要經過配置就能夠完成對事務的管理,而無需手動編程
方便程序的測試
Spring對Junit4支持,能夠經過註解方便的測試Spring程序
方便集成各類優秀框架
Spring不排斥各類優秀的開源框架,其內部提供了對各類優秀框架(如:Struts、Hibernate、MyBatis、Quartz等)的直接支持
下降JavaEE API的使用難度
Spring 對JavaEE開發中很是難用的一些API(JDBC、JavaMail、遠程調用等),都提供了封裝,使這些API應用難度大大下降
1.3 Spring的體系結構html
2 入門案例:(IoC)
2.1導入jar包
4 + 1 : 4個核心(beans、core、context、expression) + 1個依賴(commons-loggins…jar)
java
2.2目標類
提供UserService接口和實現類
得到UserService實現類的實例
以前開發中,直接new一個對象便可。學習spring以後,將由Spring建立對象實例–> IoC 控制反轉(Inverse of Control)
以後須要實例對象時,從spring工廠(容器)中得到,須要將實現類的全限定名稱配置到xml文件中
web
public interface UserService { public void addUser(); } public class UserServiceImpl implements UserService { @Override public void addUser() { System.out.println("a_ico add user"); } }
2.3 配置文件
位置:任意,開發中通常在classpath下(src)
名稱:任意,開發中經常使用applicationContext.xml
內容:添加schema約束
約束文件位置:spring-framework-3.2.0.RELEASE\docs\spring-framework-reference\html\ xsd-config.html
spring
<?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"> <!-- 配置service <bean> 配置須要建立的對象 id :用於以後從spring容器得到實例時使用的 class :須要建立實例的全限定類名 --> <bean id="userServiceId" class="com.itheima.a_ioc.UserServiceImpl"></bean> </beans>
2.4測試
express
@Test public void demo02(){ //從spring容器得到 //1 得到容器 String xmlPath = "com/itheima/a_ioc/beans.xml"; ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath); //2得到內容 --不須要本身new,都是從spring容器得到 UserService userService = (UserService) applicationContext.getBean("userServiceId"); userService.addUser();
3 入門案例:DI
例如:
編程
class BookServiceImpl{ //以前開發:接口 = 實現類 (service和dao耦合) //private BookDao bookDao = new BookDaoImpl(); //spring以後 (解耦:service實現類使用dao接口,不知道具體的實現類) private BookDao bookDao; setter方法 } 模擬spring執行過程 建立service實例:BookService bookService = new BookServiceImpl() -->IoC <bean> 建立dao實例:BookDao bookDao = new BookDaoImple() -->IoC 將dao設置給service:bookService.setBookDao(bookDao); -->DI <property>
3.1 目標類
建立BookService接口和實現類
建立BookDao接口和實現類
將dao和service配置 xml文件
使用api測試
3.2 dao
設計模式
public interface BookDao { public void save(); } public class BookDaoImpl implements BookDao { @Override public void save() { System.out.println("di add book"); } }
3.3 service
api
public interface BookService { public abstract void addBook(); } public class BookServiceImpl implements BookService { // 方式1:以前,接口=實現類 // private BookDao bookDao = new BookDaoImpl(); // 方式2:接口 + setter private BookDao bookDao; public void setBookDao(BookDao bookDao) { this.bookDao = bookDao; } @Override public void addBook(){ this.bookDao.save(); } }
3.4 配置文件
數組
<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"> <!-- 模擬spring執行過程 建立service實例:BookService bookService = new BookServiceImpl() IoC <bean> 建立dao實例:BookDao bookDao = new BookDaoImpl() IoC 將dao設置給service:bookService.setBookDao(bookDao); DI <property> <property> 用於進行屬性注入 name: bean的屬性名,經過setter方法得到 setBookDao ##> BookDao ##> bookDao ref :另外一個bean的id值的引用 --> <!-- 建立service --> <bean id="bookServiceId" class="com.itheima.b_di.BookServiceImpl"> <property name="bookDao" ref="bookDaoId"></property> </bean> <!-- 建立dao實例 --> <bean id="bookDaoId" class="com.itheima.b_di.BookDaoImpl"></bean> </beans>
3.5 測試
緩存
@Test public void demo01(){ //從spring容器得到 String xmlPath = "com/itheima/b_di/beans.xml"; ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath); BookService bookService = (BookService) applicationContext.getBean("bookServiceId"); bookService.addBook(); }
4 依賴注入裝配Bean 基於xml
4.1屬性依賴注入
依賴注入方式:手動裝配 和 自動裝配
手動裝配:通常進行配置信息都採用手動
基於xml裝配:構造方法、setter方法
基於註解裝配:
4.1.1 構造方法
目標類
public class User { private Integer uid; private String username; private Integer age; public User(Integer uid, String username) { super(); this.uid = uid; this.username = username; } public User(String username, Integer age) { super(); this.username = username; this.age = age; }
spring配置
<!-- 構造方法注入 * <constructor-arg> 用於配置構造方法一個參數argument name :參數的名稱 value:設置普通數據 ref:引用數據,通常是另外一個bean id值 index :參數的索引號,從0開始 。若是隻有索引,匹配到了多個構造方法時,默認使用第一個。 type :肯定參數類型 例如:使用名稱name <constructor-arg name="username" value="jack"></constructor-arg> <constructor-arg name="age" value="18"></constructor-arg> 例如2:【類型type 和 索引 index】 <constructor-arg index="0" type="java.lang.String" value="1"></constructor-arg> <constructor-arg index="1" type="java.lang.Integer" value="2"></constructor-arg> --> <bean id="userId" class="com.itheima.f_xml.a_constructor.User" > <constructor-arg index="0" type="java.lang.String" value="1"></constructor-arg> <constructor-arg index="1" type="java.lang.Integer" value="2"></constructor-arg> </bean>
4.1.2 setter方法
<!-- setter方法注入 * 普通數據 <property name="" value="值"> 等效 <property name=""> <value>值 * 引用數據 <property name="" ref="另外一個bean"> 等效 <property name=""> <ref bean="另外一個bean"/> --> <bean id="personId" class="com.itheima.f_xml.b_setter.Person"> <property name="pname" value="陽志"></property> <property name="age"> <value>1234</value> </property> <property name="homeAddr" ref="homeAddrId"></property> <property name="companyAddr"> <ref bean="companyAddrId"/> </property> </bean> <bean id="homeAddrId" class="com.itheima.f_xml.b_setter.Address"> <property name="addr" value="阜南"></property> <property name="tel" value="911"></property> </bean> <bean id="companyAddrId" class="com.itheima.f_xml.b_setter.Address"> <property name="addr" value="北京八寶山"></property> <property name="tel" value="120"></property> </bean>
4.2 集合依賴注入
<!-- 集合的注入都是給<property>添加子標籤 數組:<array> List:<list> Set:<set> Map:<map> ,map存放k/v 鍵值對,使用<entry>描述 Properties:<props> <prop key=""></prop> 【】 普通數據:<value> 引用數據:<ref> --> <bean id="collDataId" class="com.itheima.f_xml.e_coll.CollData" > <property name="arrayData"> <array> <value>DS</value> <value>DZD</value> <value>屌絲</value> <value>屌中屌</value> </array> </property> <property name="listData"> <list> <value>於嵩楠</value> <value>曾衛</value> <value>楊煜</value> <value>曾小賢</value> </list> </property> <property name="setData"> <set> <value>停封</value> <value>薄紙</value> <value>關係</value> </set> </property> <property name="mapData"> <map> <entry key="jack" value="傑克"></entry> <entry> <key><value>rose</value></key> <value>肉絲</value> </entry> </map> </property> <property name="propsData"> <props> <prop key="高富帥">嫐</prop> <prop key="白富美">嬲</prop> <prop key="男屌絲">挊</prop> </props> </property> </bean>
5 依賴注入裝配Bean 基於註解
註解:就是一個類,使用@註解名稱
開發中:使用註解 取代 xml配置文件。
1.@Component取代<bean class="">
@Component("id") 取代 <bean id="" class="">
2.web開發,提供3個@Component註解衍生註解(功能同樣)取代
@Repository :dao層
@Service:service層
@Controller:web層
3.依賴注入,給私有字段設值,也能夠給setter方法設值
普通值:@Value(" ")
引用值:
方式1:按照【類型】注入
@Autowired
方式2:按照【名稱】注入1
@Autowired
@Qualifier("名稱")
方式3:按照【名稱】注入2
@Resource("名稱")
4.生命週期
初始化:@PostConstruct
銷燬:@PreDestroy
5.做用域
@Scope("prototype") 多例
註解使用前提,添加命名空間,讓spring掃描含有註解類
<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:component-scan base-package="com.itheima.g_annotation.a_ioc"></context:component-scan> </beans>
Spring框架—面向切面編程(AOP)
1 什麼是AOP
在軟件業,AOP爲Aspect Oriented Programming的縮寫,意爲:面向切面編程,經過預編譯方式和運行期動態代理實現程序功能的統一維護的一種技術。AOP是OOP(面向對象編程)的延續,是軟件開發中的一個熱點,也是Spring框架中的一個重要內容,是函數式編程的一種衍生範型。利用AOP能夠對業務邏輯的各個部分進行隔離,從而使得業務邏輯各部分之間的耦合度下降,提升程序的可重用性,同時提升了開發的效率。
AOP採起橫向抽取機制,取代了傳統縱向繼承體系重複性代碼
經典應用:事務管理、性能監視、安全檢查、緩存 、日誌等
Spring AOP使用純Java實現,不須要專門的編譯過程和類加載器,在運行期經過代理方式向目標類織入加強代碼
AspectJ是一個基於Java語言的AOP框架,Spring2.0開始,Spring AOP引入對Aspect的支持,AspectJ擴展了Java語言,提供了一個專門的編譯器,在編譯時提供橫向代碼的織入
2 AOP實現原理
aop底層將採用代理機制進行實現。
接口 + 實現類 :spring採用 jdk 的動態代理Proxy。
實現類:spring 採用 cglib字節碼加強。
3 AOP術語【掌握】
1.target:目標類,須要被代理的類。例如:UserService
2.Joinpoint(鏈接點):所謂鏈接點是指那些可能被攔截到的方法。例如:全部的方法
3.PointCut 切入點:已經被加強的鏈接點。例如:addUser()
4.advice 通知/加強,加強代碼。例如:after、before
5. Weaving(織入):是指把加強advice應用到目標對象target來建立新的代理對象proxy的過程.
6.proxy 代理類
7. Aspect(切面): 是切入點pointcut和通知advice的結合
一個線是一個特殊的面。
一個切入點和一個通知,組成成一個特殊的面。
4 AOP實現方式
4.1手動方式
4.1.1JDK動態代理
JDK動態代理 對「裝飾者」設計模式 簡化。使用前提:必須有接口
1.目標類:接口 + 實現類
public interface UserService { public void addUser(); public void updateUser(); public void deleteUser(); }
2.切面類:用於存通知 MyAspect
public class MyAspect { public void before(){ System.out.println("雞首"); } public void after(){ System.out.println("牛後"); } }
3.工廠類:編寫工廠生成代理
public class MyBeanFactory { public static UserService createService(){ //1 目標類 final UserService userService = new UserServiceImpl(); //2切面類 final MyAspect myAspect = new MyAspect(); /* 3 代理類:將目標類(切入點)和 切面類(通知) 結合 --> 切面 * Proxy.newProxyInstance * 參數1:loader ,類加載器,動態代理類 運行時建立,任何類都須要類加載器將其加載到內存。 * 通常狀況:當前類.class.getClassLoader(); * 目標類實例.getClass().get... * 參數2:Class[] interfaces 代理類須要實現的全部接口 * 方式1:目標類實例.getClass().getInterfaces() ;注意:只能得到本身接口,不能得到父元素接口 * 方式2:new Class[]{UserService.class} * 例如:jdbc 驅動 --> DriverManager 得到接口 Connection * 參數3:InvocationHandler 處理類,接口,必須進行實現類,通常採用匿名內部 * 提供 invoke 方法,代理類的每個方法執行時,都將調用一次invoke * 參數31:Object proxy :代理對象 * 參數32:Method method : 代理對象當前執行的方法的描述對象(反射) * 執行方法名:method.getName() * 執行方法:method.invoke(對象,實際參數) * 參數33:Object[] args :方法實際參數 * */ UserService proxService = (UserService)Proxy.newProxyInstance( MyBeanFactory.class.getClassLoader(), userService.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //前執行 myAspect.before(); //執行目標類的方法 Object obj = method.invoke(userService, args); //後執行 myAspect.after(); return obj; } }); return proxService; } }
4.測試
@Test public void demo01(){ UserService userService = MyBeanFactory.createService(); userService.addUser(); userService.updateUser(); userService.deleteUser(); }
4.1.2 CGLIB字節碼加強
沒有接口,只有實現類。
採用字節碼加強框架 cglib,在運行時 建立目標類的子類,從而對目標類進行加強。
工廠類
public class MyBeanFactory { public static UserServiceImpl createService(){ //1 目標類 final UserServiceImpl userService = new UserServiceImpl(); //2切面類 final MyAspect myAspect = new MyAspect(); // 3.代理類 ,採用cglib,底層建立目標類的子類 //3.1 核心類 Enhancer enhancer = new Enhancer(); //3.2 肯定父類 enhancer.setSuperclass(userService.getClass()); /* 3.3 設置回調函數 , MethodInterceptor接口 等效 jdk InvocationHandler接口 * intercept() 等效 jdk invoke() * 參數一、參數二、參數3:以invoke同樣 * 參數4:methodProxy 方法的代理 * * */ enhancer.setCallback(new MethodInterceptor(){ @Override public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { //前 myAspect.before(); //執行目標類的方法 Object obj = method.invoke(userService, args); // * 執行代理類的父類 ,執行目標類 (目標類和代理類 父子關係) methodProxy.invokeSuper(proxy, args); //後 myAspect.after(); return obj; } }); //3.4 建立代理 UserServiceImpl proxService = (UserServiceImpl) enhancer.create(); return proxService; } }
4.2半自動
讓spring 建立代理對象,從spring容器中手動的獲取代理對象
4.2.1目標類
public interface UserService { public void addUser(); public void updateUser(); public void deleteUser(); }
4.2.2切面類
/**
* 切面類中肯定通知,須要實現不一樣接口,接口就是規範,從而就肯定方法名稱。
* * 採用「環繞通知」 MethodInterceptor
*
*/
public class MyAspect implements MethodInterceptor { @Override public Object invoke(MethodInvocation mi) throws Throwable { System.out.println("前3"); //手動執行目標方法 Object obj = mi.proceed(); System.out.println("後3"); return obj; } }
4.2.3Spring 配置
<!-- 1 建立目標類 --> <bean id="userServiceId" class="com.itheima.b_factory_bean.UserServiceImpl"></bean> <!-- 2 建立切面類 --> <bean id="myAspectId" class="com.itheima.b_factory_bean.MyAspect"></bean> <!-- 3 建立代理類 * 使用工廠bean FactoryBean ,底層調用 getObject() 返回特殊bean * ProxyFactoryBean 用於建立代理工廠bean,生成特殊代理對象 interfaces : 肯定接口們 經過<array>能夠設置多個值 只有一個值時,value="" target : 肯定目標類 interceptorNames : 通知 切面類的名稱,類型String[],若是設置一個值 value="" optimize :強制使用cglib <property name="optimize" value="true"></property> 底層機制 若是目標類有接口,採用jdk動態代理 若是沒有接口,採用cglib 字節碼加強 若是聲明 optimize = true ,不管是否有接口,都採用cglib --> <bean id="proxyServiceId" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="interfaces" value="com.itheima.b_factory_bean.UserService"></property> <property name="target" ref="userServiceId"></property> <property name="interceptorNames" value="myAspectId"></property> </bean>
4.2.4 測試
@Test public void demo01(){ String xmlPath = "com/itheima/b_factory_bean/beans.xml"; ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath); //得到代理類 UserService userService = (UserService) applicationContext.getBean("proxyServiceId"); userService.addUser(); userService.updateUser(); userService.deleteUser(); }
4.3全自動
從spring容器得到目標類,若是配置aop,spring將自動生成代理。
4.3.1 Spring配置
<?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:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- 1 建立目標類 --> <bean id="userServiceId" class="com.itheima.c_spring_aop.UserServiceImpl"></bean> <!-- 2 建立切面類(通知) --> <bean id="myAspectId" class="com.itheima.c_spring_aop.MyAspect"></bean> <!-- 3 aop編程 3.1 導入命名空間 3.2 使用 <aop:config>進行配置 proxy-target-class="true" 聲明時使用cglib代理 <aop:pointcut> 切入點 ,從目標對象得到具體方法 <aop:advisor> 特殊的切面,只有一個通知 和 一個切入點 advice-ref 通知引用 pointcut-ref 切入點引用 3.3 切入點表達式 execution(* com.itheima.c_spring_aop.*.*(..)) 選擇方法 返回值任意 包 類名任意 方法名任意 參數任意 --> <aop:config proxy-target-class="true"> <aop:pointcut expression="execution(* com.itheima.c_spring_aop.*.*(..))" id="myPointCut"/> <aop:advisor advice-ref="myAspectId" pointcut-ref="myPointCut"/> </aop:config> </beans>
4.3.2 測試
@Test public void demo01(){ String xmlPath = "com/itheima/c_spring_aop/beans.xml"; ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath); //得到目標類 UserService userService = (UserService) applicationContext.getBean("userServiceId"); userService.addUser(); userService.updateUser(); userService.deleteUser(); }