spring框架介紹以及簡單使用


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的體系結構

這里寫圖片描述

2 入門案例:(IoC)

2.1導入jar包
  • 4 + 1 : 4個核心(beans、core、context、expression) + 1個依賴(commons-loggins…jar)
    這里寫圖片描述
    這里寫圖片描述
2.2目標類
  • 提供UserService接口和實現類
  • 獲得UserService實現類的實例
    之前開發中,直接new一個對象即可。學習spring之后,將由Spring創建對象實例–> IoC 控制反轉(Inverse of Control)
    之后需要實例對象時,從spring工廠(容器)中獲得,需要將實現類的全限定名稱配置到xml文件中
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
<?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測試
   @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
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> 
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12

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() * 參數1、參數2、參數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(); }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM