WEB框架之Spring基礎應用

目錄

 


一、Spring基礎


1.IoC和DI的思想

  • 如果沒有IoC(控制反轉)和DI(依賴注入),調用者需要使用某個對象,其自身就得負責該對象該對象所依賴對象的創建和組裝;
  • 通過IoC和DI的思想,就是將原本在程序中手動創建對象的控制權,交由Spring框架來管理;對象的管理和依賴注入交給框架去完成;
  • IoC的實現方式:依賴注入(Dependency Injection,簡稱DI,最常用),還有一種方式叫“依賴查找”(Dependency Lookup)
  • 注入的兩種方式:構造方法注入、set方法注入
  • spring配置的三種方式: 配置xml文件  、 註解方式annotation 、 使用Configuration註解代替xml文件(java Configuration);

2.getBean方法

  • 按照bean的名字查找:world=(HelloWorld) factory. getBean ("helloWorld") ;
  • 按照bean的類型查找:world = factory.getBean (HelloWorld.class) ;
  • 按照名字和類型查找: (推薦):world=factory.gecBean ("helloWorld", HelloWorld.class) ;

3.Spring基本配置

  • Bean中的id和name屬性:spring3.1之後相同,可以起多個別名使用逗號或者空格分開;
  • xml文件分割:使用<import resource = "classpath:cn/wolfcode/day1/02_hello/hello.xml"/>進行組合;

4.日誌系統

  • 日誌分類:log4j、jcl、jul(jdk自帶)、slf4j、logback、simple-log
  • jcl:他不直接記錄日誌(抽象層),他是通過第三方記錄日誌優先原則匹配 log4j > jul 優先級
  • slf4j:他也不記錄日誌(抽象層),通過綁定器綁定一個具體的日誌記錄來完成日誌記錄,log4j 、 jul、logback

spring4當中依賴的是原生的jcl

spring5使用的spring的jcl(spring改了jcl的代碼),採用優先原則匹配(默認綁定jul

springboot使用slf4j抽象層


二、Ioc容器


1.Ioc容器

  • BeanFactory: Spring最底層的接口,只提供了的IoC功能,負責創建、組裝、管理bean;使用了懶加載,getBean時候纔會初始化Bean;
  • ApplicationContext接口:繼承了BeanFactory,除此之外還提供AOP集成、國際化處理、事件傳播、統一資源加載等功能;在初始化容器的時候就會初始化Bean;

1.1.bean實例化方式(需要使用@Autowired註解來聲明)

  • 構造器實例化(無參數構造器);
  • 靜態工廠方法實例化:解決系統遺留問題;
  • 實例工廠方法實例化:解決系統遺留問題;
  • 實現FactoryBean接口實例化;

ps:都需要在xml文件裏進行設置;

1.2.bean作用域

  • singlecon:單例,在Spcing IoC容器中僅存在一個bean實例(默認的scope);
  • prototype:多例,每次從容器中調用Bean時,都返回一個新的實例,即每次調用getBean()時,相當於執行new XxxBean(): 會在容器啓時創建對象;
  • request:用於web開發,將Bean加入request範圍,request.setAttribute("xxx"),在同一個reques獲得同一個Bean;
  • session:用於web開發, 將Bean放入Session範圍,在同一個Session中獲得同一個Bean;
  • globalSession: 一般用於porlet應用環境,分佈式系統存在全局session概念(單點登錄),如果不是porlet環境,globalSession等同於Session;

1.3.bean的創建和銷燬

  • init-method: bean生命週期初始化方法,bean創建後會進行調用;
  • destroy-method:容器被銷燬的時候,如果bean被容器管理,bean銷燬之前調用該方法;

ps:單例bean會執行銷燬方法,多例bean是不會銷燬容器的,因爲bean可能有多個容器可能會再次創建(因爲bean要往容器註冊),造成資源浪費;

2.DI依賴注入

  • 指Spring創建對象的過程中,將對象依賴屬性(常量,對象,集合)通過設置值給該對象。
  • 可以通過調用對象的setter方法.
  • 可以在創建對象的時候(調用構造器),同時設置對象的屬性值.

3.DI註解

使用@Autowired註解,是Spring規範提供的;

  • Autowired註解尋找bean的方式:
  • 首先按照依賴對象的類型找,如果找到就成功;
  • 如果在Spring上下文中找到多個匹配的類型,再按照屬性名字去找,如果沒有匹配報錯;
  • 可以配合@Qualifier設置名稱去查找;

使用@Resource註解(默認使用name進行查找,可以指定name和type屬性),是JavaEE規範提供的;

4.IoC註解

使用@Component ("myDataSource") 組件如果不寫value屬性值,此時bean的id默認是類的首字母小寫 ;

  • 等價於<bean id="myDataSource" class="cn.wolfcode.ioc.MyDataSource"/ >,但是需要在xml進行IoC容器註解配置<context:component-scan base-package="com.miaosha.*"/>
  • 類似@Service,@Controller,@Repository註解,全部放在類上;@Component(泛指組件)
  • 配置bean作用域需要加入@Scope ("prototype");
  • 配置init和destroy方法需要在對應方法,加上註解@PostConstruct;@PreDestroy;

5.其他註解

  • @Bean註解:用於告訴方法,產生一個Bean對象,然後這個Bean對象交給Spring管理,需要配合@Configuration註解進行使用。
  • @Autowired默認是根據類型進行注入的,因此如果有多個類型一樣的Bean候選者,則需要限定其中一個候選者使用,在類的構造方法執行之後運行。
  • @PostConstruct 註解的方法將會在依賴注入完成後被自動調用,貼在方法上進行執行。

ps:執行的順序Constructor >> @Autowired >> @PostConstruct

  • @Qualifier註解在使用名稱來進行限定
  • @Profile註解進行配置文件的區分符。
  • @Configuration類似於@Component組件,裏面可以包含注入依賴多個bean,相當一個bean。

ps:Component註解也會當做配置類,但是並不會爲其生成CGLIB代理Class(可能new多個實例對象);Configuration會進行代理攔截從BeanFactory裏獲取創建好的實例(bean的作用域默認爲單例)。

  • @Primary當@Autowired的類型有多個實現類的時候,需要進行在類上聲明一個主類,否則會報錯。
  • @ConfigurationProperties(prefix = "person")從properties文件配置屬性。
  • @Value註解 ① ${ property : default_value } 從.properties文件獲取  ② #{ obj.property? :default_value }從Bean對象獲取

  • @Async註解標記的方法,在執行時會被AOP處理爲異步調用,調用此方法處直接返回,@Async標註的方法使用其他線程執行。

  • @ConfigurationProperties,配置屬性聲明前綴,配上類的屬性,在properties文件等地方可以進行賦值;


三、AOP面向切面


1.代理模式

  • 客戶端調用實際類,要對該調用進行增強可以通過代理類對調用進行攔截增強,代理類組合了實際類,讓調用面向代理類而不是實際類;
  • 客戶端使用的都是代理對象而不是實際對象,通過代理類在客戶端和實際對象之間起到中介的作用;

1.1靜態代理

  • 在程序運行前就已經存在代理類的字節碼文件,代理對象和真實對象的關係在運行前就確定了。

1.2動態代理

  • 在程序運行期間由JVM通過反射機制動態的生成(生成代理類,獲取構造函數,通過構造函數new代理實例),代理對象和真實對象的關係是在程序運行時期才確定的

2.動態代理的實現

  • 針對實際對象target實現了接口:使用JDK動態代理;(Advice增強代理類,實現reflect裏的InvocationHandler接口,包含target要增強對象(實際對象))
  • 原理:生成的代理類實現了實際對象的接口;
  • 針對實際對象target沒有接口無法實現:使用CGLIB或Javassist組件;(Advice增強代理類,實現cglib裏的InvocationHandler接口,包含target要增強對象(實際對象))
  • 原理:生成的代理類繼承了實際對象;

3.AOP面向切面編程

  • OOP:面向對象的組合和繼承可以一定程度消除重複,但是編程複雜代碼耦合度大;

  • AOP:面向切面編程(橫切關注點,比如:打日誌、增加事務、權限驗證等)來對原有對象功能的增強,它是通過動態代理來自動生成代理類並且可以避免一個功能點要被重複寫很多遍,在OOP的基礎上解脫編程複雜度,達到解耦合;

3.1專業術語:

  • JoinPoint:需要被增強的方法,代表哪一個方法需要被增強;
  • Pointcut:切入點,哪些方法需要被增強,是JoinPoint的一個集合(用表達式來進行匹配出JoinPoint);
  • Advice:增強(通知),當攔截到JoinPoint後,在方法執行的某一時機(前置/後置/異常/最終/環繞增強)進行操作,進行增強;
  • Aspect:切面=Pointcut+Advice(等價Advicor通知器),對很多個JoinPoint進行增強,形成一個切面; 
  • Target:目標對象,被代理的目標對象;
  • Proxy:一個target類被AOP織入增強後,創建出來的代理對象;
  • Weaving:織入,把Advice加到Target上,創建出來代理對象的過程;
  • Advisor:通知器是一個特殊的切面,需要xml和java代碼一塊實現;切面可以只用xml配置;當使用註解時沒有該概念

ps:環繞增強代表前四個增強的合體(before,after,throw,finally);執行真實對象的方法,可以給增強方法傳參ProceedingJoinPoint來獲取被增強方法;

3.2Pointcut語法

  • AspectJ 是一個面向切面的框架,AspectJ定義了AOP語法spring只借鑑了AspectJ的語法並且一般情況springAOP夠用,如果是第三方框架不能整合spring那麼或許需要使用AspectJ
  • 括號中".."表示任意個參數,不帶括號"xxx.."表示包含xxx以及xxx的任意子包,"*"代表一個單詞;
  • 比如:execution(*  cn.volfcode.crm.service.*.*(..))  ---  代表(返回值  方法的全限定名(參數...))
  • execution匹配精確到方法,within精確到類,args只匹配指定參數類型和指定參數數量的方法,與包名和類名無關
  • @annotation匹配帶有com.chenss.anno.xxx註解的方法,
  • target匹配目標對象的類型,this匹配的是當前代理對象的類型(cglib的target和this是父子關係,jdk的是兩個實現同一接口的類獨立、不相干)

4.Spring的AOP開發

4.1配置xml文件:

  • 配置Aspect切面(增強的方式)、配置要被增強的方法、配置方法增強的具體時機(前置/後置....;並且需要引用要被增強的方法);

4.2.註解配置:

  • 使用IoC和DI的註解,可以去掉bean的聲明;(需要在xml文件配置對應的註解解析器)
  • 在類上使用@Aspect註解配置切面,使用@Pointcut獲取到所有要被增強的方法(貼在方法上!),使用@Before等註解貼在增強的方式(需要引用pointcut要被增強的方法纔可!)
  • 最後配置AOP註解解析器<aop:aspectj-autoproxy/>;

4.3多例切面

  • 默認的切面是單例的,儘管目標類是多例的也會是同一個代理類進行代理,可以配置切面prethis以及作用域

四、註解驅動開發


1.Bean註解介紹

@Configuration 配置類等價於xml配置文件,聲明這是一個配置類(java config的配置方式

@Bean  給容器註冊一個Bean,class代表返回值的類型,id/name默認是用方法名

@ComponentScan  配置包掃描的路徑

讓標註了@Controller 、@Service、@Repository、@Component的類被從指定路徑掃描到,

支持重複註解@Repeatable使用@ComponentScans來組合多個ComponentScan ,

每個@Filter可以使用指定類型來進行過濾(自定義類型過濾跟標註的註解無關,只跟掃描的包路徑有關),可以使用註解/正則/AspectJ表達式來進行過濾(不光跟包路徑有關,還跟註解有關),

當類特別多還按照類路徑掃描的話會非常慢,可以使用spring5的index給類構建索引來提高啓動效率

@Scope 給Bean註解設置定義域,默認爲單例且在容器創建時候創建Bean

@Lazy  懶加載在第一次獲取的時候進行創建對象

ps:單例bean默認不爲懶加載,多例bean默認爲懶加載。

@Conditional 按照條件註冊Bean,自定義的實現類需要實現Condintal接口的match方法

@Import 快速給容器導入一個Bean組件,id默認爲組件的全類名 。

可以實現ImportSelector接口  返回需要導入的組件的全類名。

可以實現ImportBeanDefinitionRegistrar接口  自定義註冊Bean

ps:實現FactoryBean接口可以創建一個Bean,配合@Bean註解可以實現,如果獲取工廠Bean本身,需要 給id前加一個&。

2.Bean的生命週期

 * 構造(對象創建)
 *         單實例:在容器啓動的時候創建對象
 *         多實例:在每次獲取的時候創建對象
 * 
 * BeanPostProcessor.postProcessBeforeInitialization
 * 初始化:
 *         對象創建完成,並賦值好,調用初始化方法。。。
 * BeanPostProcessor.postProcessAfterInitialization
 * 銷燬:
 *         單實例:容器關閉的時候
 *         多實例:容器不會管理這個bean;容器不會調用銷燬方法;

3.Bean賦值

@Value 給字段進行賦值,可以寫基本類型,可以使用EL表達式#{20-2},可以使用${}取配置文件的值,

@PropertySource ("classpath:/db.properties")給類聲明配置文件的位置,可以使用PropertySources來聲明多個PropertySource ,PropertySource 也可以指定多個值,

ps:最終配置文件裏的信息都會在applicationContext環境裏面。

@AutoWired  自動裝配bean,不提供name和type參數先按照type類型找如果有多個在按照屬性name去找

用在字段上(較爲常用)private SoakService soakService;

用在參數上 、用在構造方法上、用在set方法上 

@Qualifier  可以明確指定要裝配的bean,配合@AutoWired 使用

@Primary  進行自動裝配的時候,默認使用首先的bean

@Resource  屬於JSR規範(提供了name和type參數,默認按照name找,如果有多個按照type找;如果只指定一個找到多個或者找不到會報錯  ) 

@Lookup 當單例bean依賴多例bean,因爲單例只會初始化一次,這樣會導致多例變爲單例,可以調用方法時可以實現ApplicationContextAware接口重新getBean來解決,還可以使用該註解來解決

@Profile  動態的激活和切換一系列組件功能,指定組件在具體哪個環境下注冊到容器中,不指定任何環境下都能註冊這個組件

加了環境標識的bean,只有這個環境被激活的時候才能註冊到容器中

指定命令行參數-Dspring.profile.active=test

使用代碼的方式applicationContext.getEnvironment().setActiveProfiles(...)

4.AOP註解

@Pointcut 抽取公共的切入點(要被增強的方法)表達式

@Before/@After/@AfterReturning/@AfterThrowing/@Around   增強(通知)方法

@Aspect  當前類是一個切面類(包含切入點和增強/通知的類)

@EnableAspectJAutoProxy  給配置類(@Configuration)中激活動態代理


五、DAO持久化


1.事務

在一個事務方法中,調用了其他事務的方法,此時事務該如何傳遞,按照什麼規則傳播.

1.1事務傳播規則情況一:需要遵從當前事務

  • REQUIRED: 如果當前存在一個事務,則加入到該事務中,否則,新建一個事務;(使用比較多)
  • SUPPORTS: 支持當前事務。如果當前存在事務,則使用該事務否則以非事務形式運行;
  • MANDATORY: 必須要存在事務,如果當存在事務,就使用該事務,否則,拋出異常;

1.2事務傳播規則情況二:不遵從當前事務

  • REQUIRES_NEW:不管當前是否存在事務,都會新開啓一個事務 必須是一個新的事務;(使用的比較多)
  • NOT_SUPPORTED: 以非事務方式執行,如果當前存在事務,把當前事務暫停;
  • NEVER :不支持事務,如果當前存在事務,拋出一個異常;

1.3事務傳播規則情況三:寄生事務(外部事務/內部事務/嵌套事務)

  • HESTED:寄生事務,如果當前存在事務,則在外部事務內執行;如果當前不存在事務則創建一個新的事務;
  • 寄生事務可以通過數據庫savePoint (保存點)來實現,寄生事務可以回滾的,但是他的回滾不影響外部事務.但是外部事務的回滾會影響寄生事務.

1.4<tx:method/>元素的屬性(要被增強的方法)

  • name:事務管理的方法名稱,支持使用通配符方式:*匹配方法的模式
  • propagation:事務的傳播規則,默認REQUIRED
  • isolation:事務的隔離級別,默認DEFAULT跟隨數據表
  • timeout:事務超時時間,默認跟隨數據庫
  • read-only:是否是隻讀事務,針對查詢操作
  • rollback-for:遇到什麼類型的異常做事務回滾,默認java.lang.RuntimeException
  • no- rol lback-for:遇到什麼類型的異常不回滾

2.事務的配置

  • 基於xml:配置增強的方式、配置增強的一些設置以及對應的Joinpoint、配置切面增強和切入點Pointcut;
  • 基於註解:配置@Transactional(該註解可以貼在類/方法上)在service類上,配置tx註解解析器和事務管理實際類(IOC和DI的註解解析器也得配置);
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章