spring技術體系學習筆記
目錄
1.spring簡介
1.1 什麼是spring?
- spring產生於2003年,輕量級javase/ee一站式(表示層、業務邏輯層、資料持久層)開源框架。
- ejb:javabean包含私有屬性,公開的訪問器,以及無參構造;
- spring的官網:http://spring.io/
1.2 spring在3層架構中的地位?
- 表示層:SpringMVC/struts2
- 業務邏輯層:Spring Framework,注意區分當前講的spring是整個spring的體系結構包含Spring Framework。
- 資料持久層:Mybatis/Hibernate
1.3 spring的產生背景?點選檢視spring產生的背景,創始人堪稱大師級人物,學習的榜樣
1.4 spring的優點?
- 方便解耦,簡化開發:spring是工廠,負責建立物件以及物件關係維護。
- 支援aop程式設計(面向切面程式設計)
- sprint支援對優秀框架的整合(mybatis,struts2...)
- spring支援對javaee api的簡化
- spring支援對junit的整合
1.5 spring的體系結構?
1.6 spring的核心?IOC和AOP
什麼是Ioc?Inversion of Control,即“控制反轉”,不是什麼技術,而是一種設計思想。在Java開發中,Ioc意味著將物件建立和依賴的管理許可權反轉給spring容器。DI,即Dependency Injection,依賴注入。
什麼是AOP?面向切面程式設計,通過預編譯方式和執行期動態代理實現程式功能的統一維護的一種技術。利用AOP可以對業務邏輯的各個部分進行隔離,從而使得業務邏輯各部分之間的耦合度降低,提高程式的可重用性,同時提高了開發的效率。
2.spring入門案例
案例:
- UserService介面和UserServiceImpl實現類模擬業務邏輯層
- UserDao介面和UserDaoImpl實現類模擬資料持久化層
- 初步使用spring
步驟:
- 建立Java專案,匯入jar包:4個核心jar包+commons-logging(日誌增強,mybatis/lib目錄下有)
- spring-beans-4.1.6.RELEASE.jar
- spring-context-4.1.6.RELEASE.jar
- spring-core-4.1.6.RELEASE.jar
- spring-expression-4.1.6.RELEASE.jar
- commons-logging-1.2.jar
- 編寫介面+實現類
- 在src目錄下建立並編寫配置檔案applicationContext.xml
- 獲取配置資訊並執行程式
程式碼:
介面及實現類
package dao;
public interface UserDao {
void addUser();
void deleteUser();
}
package dao.impl;
import dao.UserDao;
public class UserDaoImpl implements UserDao {
@Override
public void addUser() {
System.out.println("新增使用者");
}
@Override
public void deleteUser() {
System.out.println("刪除使用者");
}
}
package service;
public interface UserService {
void addUser();
void deleteUser();
}
package service.impl;
import dao.UserDao;
import service.UserService;
public class UserServiceImpl implements UserService {
//介面引用+構造器
//介面引用+setter方法
private UserDao dao;
public void setDao(UserDao dao){
this.dao = dao;
}
public UserServiceImpl(UserDao dao){
this.dao = dao;
}
@Override
public void addUser() {
dao.addUser();
}
@Override
public void deleteUser() {
dao.deleteUser();
}
}
配置檔案:applicationContext.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"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- bean:代表配置管理一個物件 id:唯一表示 class:類的完全限定名稱-->
<bean id="userdao" class="dao.impl.UserDaoImpl"></bean>
<!-- 呼叫無參構造+setter方法建立物件 -->
<!-- <bean id="userservice" class="service.impl.UserServiceImpl">
給屬性賦值 name:屬性名稱 value:賦值簡單型別 ref:引用型別賦值,使用容器中以後的bean物件userdao
<property name="dao" ref="userdao"></property>
</bean> -->
<!-- 使用有參構造建立物件 -->
<bean id="userservice" class="service.impl.UserServiceImpl">
<!-- 構造引數:name:引數名稱 value:簡單型別賦值 ref:引用型別賦值 index:引數索引 type:引數型別-->
<!-- <constructor-arg name="dao" ref="userdao" index="" type=""></constructor-arg> -->
<constructor-arg index="0" ref="userdao" ></constructor-arg>
</bean>
</beans>
讀取配置資訊並執行程式
package test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import service.UserService;
public class Test {
public static void main(String[] args) {
//建立管理物件的許可權都是開發者的
//spring容器先建立和管理dao物件(配置檔案來實現)
//從spring容器中獲取dao物件
/*ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao dao = ac.getBean("userdao",UserDao.class);
dao.addUser();
dao.deleteUser();*/
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userservice = ac.getBean("userservice", UserService.class);
userservice.addUser();
userservice.deleteUser();
}
}
3.bean的生命週期
bean生命週期圖示(關鍵階段用紅框標記,下面逐個解釋。)
BeanPostProcessors(Pre-initialization 和 Post-initialization):
- 有時希望咱Spring IoC容器初始化受管Bean前、屬性設定後對該Bean先做一些預處理,或者在容器銷燬受管Bean之前釋放自己的資源。
- Spring IoC提供了多種方法來實現受管Bean的預處理和後處理。
- Spring中定義了BeanPostProcessors介面(如下方程式碼)。
- 若這個介面的某個實現類被註冊到容器,那麼該容器的每個受管Bean在呼叫初始化方法前,都會獲得該介面實現類的一個回撥。
- 容器呼叫介面定義的方法時會將該受管Bean的例項和名字通過引數傳入方法,經過處理後通過方法的返回值返回給容器。
- 使用ApplicationContext容器會在配置檔案自動尋找實現了BeanPostProcessor介面的bean,然後自動註冊。
package org.springframework.beans.factory.config;
import org.springframework.beans.BeansException;
public interface BeanPostProcessor {
Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}
Call custom init-method 和 Call custom destory-method:呼叫物件自定義初始化方法和自定義銷燬方法。使用步驟如下:
- 在User類中定義init()和destory()方法
- 在applicationContext.xml配置檔案中註冊User,程式碼<bean id="user" class="pojo.User" init-method="init" destory-method="destory"></bean>
- 獲取註冊bean,則自動呼叫init()方法,關閉容器則自動呼叫destory()方法
- 關閉容器的程式碼:ac.getClasss().getMethod("close").invoke(ac);//ac就是ApplicationContext物件
Bean is Ready To Use / Container is Shutdown:表示物件以準備好可以使用 / 表示關閉spring容器
4.註解實現bean的裝配
常用註解:
- @Component:建立物件,等價於<bean class=" "></bean>
- @Component("id"):建立物件,等價於<bean id=" " class=" "></bean>
- @Controller:用於表示層建立物件(主要是為了區分,其實都可以通用)
- @Service:用於業務邏輯層建立物件
- @Repository:用於資料持久層用於建立物件
- @Autowired:按照型別自動注入(找不到:不注入;找到1個:注入;找到多個:異常)
- 按照名稱注入:
- @Autowird 和 @Qualifiler("name")
- @Resource(name="name")
使用步驟:
- 建立Java專案,匯入jar包
- spring 4+1(5個包)
-
spring-aop.jar
- 分包:dao和dao.impl,service和service.impl
- 編寫介面及實現類並註解實現類
- 編寫applicationContext.xml配置檔案:掃描註解並建立物件
- 讀取配置並執行
示例程式碼:
dao和service包或子包中的程式碼
package dao;
public interface UserDao {
void addUser();
void deleteUser();
}
package dao.impl;
import org.springframework.stereotype.Repository;
import dao.UserDao;
//資料持久層建立物件的註解,userdao是所建立物件的名字
//建立物件需要:全限定類名+物件名(可選)
@Repository("userdao")
public class UserDaoImpl implements UserDao {
@Override
public void addUser() {
System.out.println("新增使用者");
}
@Override
public void deleteUser() {
System.out.println("刪除使用者");
}
}
package service;
public interface Service {
void addUser();
void deleteUser();
}
package service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import dao.UserDao;
import service.Service;
//資料持久層建立物件的註解,service是所建立物件的名字
//這裡Service註解名和Service介面名衝突了
//建立物件需要:全限定類名+物件名(可選)
@org.springframework.stereotype.Service("service")
public class ServiceImpl implements Service {
//按照型別自動注入,注入前提是spring Ioc容器中有該型別的物件
//找不到物件:則不注入;找到1個物件:則自動注入;找到多個物件:則報異常
@Autowired
private UserDao dao;
@Override
public void addUser() {
dao.addUser();
}
@Override
public void deleteUser() {
dao.deleteUser();
}
}
spring配置檔案applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<!-- 引入了context的名稱空間,以及標籤庫 -->
<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="dao,service"></context:component-scan>
</beans>
Test測試類
package test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import service.Service;
public class Test {
public static void main(String[] args) {
//建立spring的ApplicationContext物件
ApplicationContext application = new ClassPathXmlApplicationContext("applicationContext.xml");
//獲取bean物件:第一個引數指定Ioc容器中的物件名,第二個引數指定物件型別
Service service = application.getBean("service", Service.class);
service.addUser();
service.deleteUser();
}
}
5.spring整合junit
什麼是junit?用於單元測試
如何使用junit?
- 匯入jar包:Eclipse IDE自帶,右鍵單擊專案名稱,選擇build path,再選擇add Libary,最後選擇Junit即可
- 編寫test()方法:在方法上方加上@Test註解,方法不能有返回值,不能有引數
- 執行test()方法:滑鼠游標放置在方法名稱,然後右鍵單擊,選擇run as,最後選擇JUnit Test執行
常用Junit註解:
- @Test:註解方法,表示測試單元
- @Before:在單獨執行單元前執行
- @After:在單獨執行單元后執行
- 示例程式碼:
package test;
import org.junit.After;
import org.junit.Before;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import service.Service;
public class Test {
@Before
public void before(){
System.out.println("before");
}
@After
public void after(){
System.out.println("after");
}
@org.junit.Test
public void testService(){
//建立spring的ApplicationContext物件
ApplicationContext application = new ClassPathXmlApplicationContext("applicationContext.xml");
//獲取bean物件:第一個引數指定Ioc容器中的物件名,第二個引數指定物件型別
Service service = application.getBean("service", Service.class);
service.addUser();
service.deleteUser();
}
}
斷言Assert:
- 在執行之前推斷程式碼的執行結果,如果推斷正確,則正常執行;若推斷錯誤,則執行失敗。
- 示例程式碼:
package test;
import org.junit.Assert;
public class Test {
@org.junit.Test
public void test(){
Assert.assertEquals("aa","aa");
}
}
spring整合junit:
匯入jar:spring-test.jar
示例程式碼:在前面註解注入程式碼的基礎上修改如下
將test包加入掃描
<?xml version="1.0" encoding="UTF-8"?>
<!-- 引入了context的名稱空間,以及標籤庫 -->
<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="dao,service,test"></context:component-scan>
</beans>
package test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import service.Service;
//設定執行器
@RunWith(SpringJUnit4ClassRunner.class)
//獲取spring配置資訊
@ContextConfiguration(locations="classpath:applicationContext.xml")
public class Test {
//自動依賴注入
@Autowired
private Service service;
@org.junit.Test
public void test(){
service.addUser();
service.deleteUser();
}
}
6.代理
代理定義:物件訪問前後實現預處理、過濾處理。比如在不改變原有增刪改查程式碼的情況下,新增事務
代理分類:靜態代理和動態代理
靜態代理:
- 編譯期間為每個委託類建立代理類
- 代理類與委託類實現同一個介面
- 示例程式碼:
//介面
package service;
public interface UserService {
void addUser();
void deleteUser();
}
package service.impl;
import service.UserService;
/**
* 委託類
*/
public class UserServiceImpl implements UserService {
@Override
public void addUser() {
System.out.println("新增使用者");
}
@Override
public void deleteUser() {
System.out.println("刪除使用者");
}
}
package service.proxy;
import service.UserService;
import service.impl.UserServiceImpl;
/**
* 代理類
* 注意:代理類和委託類實現同一個介面
*/
public class UserServiceProxy implements UserService {
UserService service = new UserServiceImpl();
@Override
public void addUser() {
System.out.println("開啟事務");
service.addUser();
System.out.println("提交事務");
}
@Override
public void deleteUser() {
System.out.println("開啟事務");
service.deleteUser();
System.out.println("提交事務");
}
}
package test;
import service.UserService;
import service.proxy.UserServiceProxy;
public class Test {
@org.junit.Test
public void testServiceProxy(){
UserService service = new UserServiceProxy();
service.addUser();
service.deleteUser();
}
}
動態代理:
- 執行期間為每個委託類的物件建立代理物件。兩種方式,如下
- 介面+委託類(不需要實現類了),執行的時候直接建立代理物件
- 示例程式碼:
package service;
public interface UserService {
void addUser();
void deleteUser();
}
package service.impl;
import service.UserService;
/**
* 委託類
*/
public class UserServiceImpl implements UserService {
@Override
public void addUser() {
System.out.println("新增使用者");
}
@Override
public void deleteUser() {
System.out.println("刪除使用者");
}
}
package test;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import service.UserService;
import service.impl.UserServiceImpl;
public class Test {
//無侵入式增強
@org.junit.Test
public void testServiceProxy(){
//1.建立委託類物件
UserService service = new UserServiceImpl();
//2.為委託類物件建立動態代理物件
UserService proxy = (UserService) Proxy.newProxyInstance(
service.getClass().getClassLoader(),
service.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("開啟事務");
//手動呼叫方法
Object obj = method.invoke(service, args);
System.out.println("提交事務");
return obj;
}
});
//3.呼叫代理物件
proxy.addUser();
proxy.deleteUser();
}
}
7.aop
什麼是aop?
- 面向切面程式設計;
- 採用橫向抽取的方式,在執行階段將增強程式碼織入目標物件的一種思想;
- 底層採用的是動態代理。
什麼是橫向抽取?http://www.bubuko.com/infodetail-2060817.html
aop應用場景有哪些?事務管理,日誌系統,效能監測等。
aop框架有哪些?
- spring aop(spring-aop.jar)
- aspectj(aspecty.jar)
- jboss
aop的專業術語:
- target:目標物件。
- advice:通知,增強程式碼(遵循特定規範的增強程式碼)。
- joinpoint:連線點,即目標物件的方法。
- pointcut:切入點,真正新增增強程式碼的目標物件的方法。
- weaver:織入,增強程式碼新增到切入點的過程。
- aspect:切面,增強程式碼和切入點連線形成的邏輯面。
8.5 aop程式設計
配置方式實現:
- 建立Java專案並匯入jar包:
- 4+1:前面專案的jar包
- spring-aop.jar:aop框架
- aspects.jar:aspectj規範
- aopalliance-1.0.jar:aop聯盟(規範通知)
- aspectjweaver-1.8.5.jar:實現織入
- 編寫目標類
- 編寫增強類
- 編寫applicationContext.xml配置檔案
- 引人aop名稱空間及其標籤庫
- 建立目標類物件
- 建立增強類物件
- 織入
- 配置切入點
- 配置切面:呼叫前增強和呼叫後增強
- 單元測試
- @ContextConfiguration("classpath:applicationContext.xml")
- @runtime(SpringJUnit4ClassRunner.class)
- @Autowired自動注入依賴
- 程式碼如下:
package service;
public interface UserService {
void addUser();
void deleteUser();
}
package service.impl;
import service.UserService;
public class UserServiceImpl implements UserService {
@Override
public void addUser() {
System.out.println("新增使用者");
}
@Override
public void deleteUser() {
System.out.println("刪除使用者");
}
}
package aspect;
public class MyAspect {
public void before(){
System.out.println("開啟事務");
}
public void after(){
System.out.println("提交事務");
}
}
package test;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import service.UserService;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class Main {
@Autowired
private UserService service;
@Test
public void test(){
service.addUser();
service.deleteUser();
}
}
applicationContext.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: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">
<!-- 建立目標類物件 -->
<bean id="userservice" class="service.impl.UserServiceImpl"></bean>
<!-- 建立增強類物件 -->
<bean id="myaspect" class="aspect.MyAspect"></bean>
<!-- 織入 -->
<aop:config>
<!-- 配置切入點 -->
<aop:pointcut expression="execution(* service..*(..))" id="mypoiontcut"/>
<!-- 配置切面 -->
<aop:aspect ref="myaspect">
<aop:before method="before" pointcut-ref="mypoiontcut"/>
<aop:after-returning method="after" pointcut-ref="mypoiontcut"/>
</aop:aspect>
</aop:config>
</beans>
註解方式實現:
- 建立Java專案並匯入jar包:
- 4+1:前面專案的jar包
- spring-aop.jar:aop框架
- aspects.jar:aspectj規範
- aopalliance-1.0.jar:aop聯盟(規範通知)
- aspectjweaver-1.8.5.jar:實現織入
- 編寫目標類
- @Component("userservice")建立目標類物件
- 編寫增強類
- @Component("myaspect")建立增強類物件
- @Aspect建立切面
- @PointCut("execution(* service..*(..))")建立切入點
- @Before("pointCut()")呼叫前增強
- @AfterReturning("pointCut()")呼叫後增強
- 編寫applicationContext.xml配置檔案
- 引入context名稱空間及其標籤庫
- 引入aop名稱空間及其標籤庫
- 掃描上下文註解並建立物件
- 宣告自動代理
- 單元測試
- @ContextConfiguration("classpath:applicationContext.xml")
- @runtime(SpringJUnit4ClassRunner.class)
- @Autowired自動注入依賴
- 程式碼如下:
package service;
public interface UserService {
void addUser();
void deleteUser();
}
package service.impl;
import org.springframework.stereotype.Component;
import service.UserService;
@Component("userservice")
public class UserServiceImpl implements UserService {
@Override
public void addUser() {
System.out.println("新增使用者");
}
@Override
public void deleteUser() {
System.out.println("刪除使用者");
}
}
package aspect;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Component("myaspect")
@Aspect
public class MyAspect {
@Pointcut("execution(* service..*(..))")
public void pointCut(){}
@Before("pointCut()")
public void before(){
System.out.println("開啟事務");
}
@AfterReturning("pointCut()")
public void after(){
System.out.println("提交事務");
}
}
package test;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import service.UserService;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class Main {
@Autowired
private UserService service;
@Test
public void test(){
service.addUser();
service.deleteUser();
}
}
applicationContext.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"
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/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<context:component-scan base-package="aspect,service"></context:component-scan>
<aop:aspectj-autoproxy/>
</beans>