一.Spring框架概述
1,Spring是一個 開源的 輕量級的 JavaEE框架。
輕量級:體積小,jar獨立使用不需要依賴其他jar包,
開源:免費,可以提供原始碼
框架:解決開發的複雜性,簡化企業開發。
2,spring的兩個核心部分:IOC,Aop
IOC:控制反轉,把建立物件的過程交給spring進行管理。
Aop:面向切面,在不修改原始碼的情況下,進行功能的新增或增強。
3,spring框架的特點:
1),方便解耦,簡化開發:物件與物件之間的關係依賴spring。
2),Aop程式設計支援:不改變原始碼,增強功能
3),方便測試;
4),方便整合各種優秀框架。
5),方便進行食物管理,降低API的使用難度
6),java原始碼經典學習範例。
4,入門案例:
1),下載Spring5:
spring網址 : spring.io
直接下載地址:https://repo.spring.io/artifa...
還要下載一個日誌jar包,spring5依賴於這個jar包commons-login這個jar
下載連結:commons-logging-1.1.1.jar下載及Maven、Gradle引入程式碼,pom檔案及包內class -時代Java (nowjava.com)
我個人下載5.2.6
2),下載完成以後,參加一個普通的java專案,將jar匯入專案
3),使用spring
(1),建立普通類,在類中建立普通方法
public class User {
public void add(){
System.out.println("add.......");
}
}
(2),建立spring配置檔案,在配置檔案中配置檔案配置建立的物件
a,Spring配置檔案使用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">
<!--配置User物件建立-->
<bean id = "user" class = "com.yuge.User"></bean>
</beans>
b,建立測試類Test
public class Tset {
@Test
public void testAdd(){
//1.讀入上下文配置檔案
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
//2.獲取配置物件
User user = context.getBean("user", User.class);
System.out.println(user);
user.add();
}
}
c,測試結果,成功建立物件,並呼叫方法
二,IOC容器
1.IOC底層原理
1),什麼是IOC:
控制反轉,將物件的建立和物件之間的互動作用,都交給spring進行管理。
2),使用IOC的目的
為了降低耦合
3)IOC入門案例
2,IOC底層原理
1),xml解析,工廠模式,反射
2)圖解IOC底層原理
傳統方式:
工廠模式:
IOC模式:
3.IOC介面(BeanFactory)
IOC基於容器完成,IOC容器的底層就是物件工廠
1),BeanFactory介面:
IOC容器的最基本實現,是spring內部的使用介面,不提倡給開發人員使用。
2),ApplicationContext介面:
是BeanFactory的子介面,提供比BeanFactory更強大的功能,一般為開發人員使用
3),兩介面的區別
因為我們在使用Spring框架時,一般都是配合網頁使用,使用BeanFactory建立物件時,不會建立物件,而載入配置檔案的時候,是在伺服器啟動的時候,使用tomcat,都是將系統載入檔案等費事非空間的事放在tomcat啟動時完成,以提供更好的使用者體驗,所以採用ApplicationContext介面
4),applicationContext的實現類
3.IOC操作Bean管理(基於xml)
1),什麼是bean管理:
A,bean管理包括兩個步驟:Spring建立物件和Spring屬性注入
2),bean管理的實現方式:
a,基於xml配置檔案的實現方式
1.基於XML方式建立物件
id屬性:給class類路徑取個別名
class屬性:建立物件類的全路徑
XML方式建立預設物件預設使用空參構造器
2.基於XML方式的屬性注入
(1),DI:依賴注入,就是注入屬性。
DI與IOC的區別:DI是IOC的一種實現。
方式一:使用set方式注入
(a),建立類的物件,建立set方法
(b),在配置檔案中配置物件建立,配置屬性注入
方式二:使用有參構造方法注入
方式三:p名稱空間注入:
第一步:
第二步:
3.注入空值和特殊字元
一,注入空值
二,注入特殊符號
4,注入bean
1),注入外部bean
引入外部bean,用service呼叫Dao層,就是引入外部bean的過程。
2)注入內部bean 和 級聯賦值
級聯賦值方式1:不需要dept的get方法。
級聯賦值方式2:第二種方法需要建立dept的get方法。
5.注入集合屬性
0),建立Stu類,User類
package com.yuge;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class Stu {
//陣列型別
private String course[];
//List型別
private List<String> name;
//Map型別
private Map<String,String> map;
//Set型別
private Set<String> set;
//List型別中存入多個物件
private List<User> userList;
public void setUserList(List<User> userList) {
this.userList = userList;
}
public void setCourse(String[] course) {
this.course = course;
}
public void setName(List<String> name) {
this.name = name;
}
public void setMap(Map<String, String> map) {
this.map = map;
}
public void setSet(Set<String> set) {
this.set = set;
}
public void show(){
System.out.println(Arrays.toString(course));
System.out.println(name);
System.out.println(map);
System.out.println(set);
System.out.println(userList);
}
}
package com.yuge;
public class User {
private String name;
public void setName(String name) {
this.name = name;
}
public void add(){
System.out.println("add.......");
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
'}';
}
}
1).XML注入陣列型別屬性
2),XML注入List集合屬性
3),XML注入Map集合屬性
4),XML注入Map屬性
5),在集合中注入物件屬性:
<?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:m="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--配置Stu物件建立-->
<bean id="stu" class="com.yuge.Stu">
<!--注入陣列屬性-->
<property name="course">
<array>
<value>javaSe</value>
<value>Mysql</value>
</array>
</property>
<!--注入List物件-->
<property name="name">
<list>
<value>武巴</value>
<value>巴巴</value>
</list>
</property>
<!--注入Map物件-->
<property name="map">
<map>
<entry key="JAVASE" value="javase"></entry>
<entry key="SPRING" value="Spring"></entry>
</map>
</property>
<!--注入Set物件-->
<property name="set">
<set>
<value>張三</value>
<value>小三</value>
</set>
</property>
<!--在list中注入物件屬性-->
<property name="userList">
<list>
<ref bean="user1"></ref>
<bean id="user1=2" class="com.yuge.User">
<property name="name" value="李華"></property>
</bean>
</list>
</property>
</bean>
<bean id="user1" class="com.yuge.User">
<property name="name" value="李燁"></property>
</bean>
</beans>
6),建立測試類
package com.yuge.test;
import com.yuge.Stu;
import com.yuge.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.applet.AppletContext;
public class Tset {
@Test
public void testAdd(){
//載入配置檔案
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext("bean2.xml");
//建立物件
Stu stu = (Stu) applicationContext.getBean("stu");
stu.show();
}
}
7),輸出結果
8).將集合向上抽取為所有bean的公共集合
第一步:引入新的名稱空間:
第二步:使用util標籤完成list集合注入的向上抽取
建立新的Book類測試向上抽取注入list
package com.yuge;
import com.sun.xml.internal.ws.api.model.wsdl.WSDLOutput;
import java.util.List;
public class Book {
private List<String> bookList;
public void setBookList(List<String> bookList) {
this.bookList = bookList;
}
public void test(){
System.out.println(bookList);
}
}
配置XML檔案抽取注入list的方法:
<?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:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation=
"http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd">
<util:list id="list">
<value>java從入門到入土</value>
<value>python從入門到入獄</value>
</util:list>
<bean id="book" class="com.yuge.Book">
<property name="bookList" ref="list"></property>
</bean>
</beans>
執行結果:抽取成功
抽取之前的樣子:
抽取之後的樣子:
還可以抽取更多的物件。
6,Spring中的兩種bean
1)普通bean:XML中定義什麼型別就返回什麼型別
2),工廠bean:XML中定義一個型別,可以返回其他型別
第一步:建立類作為工廠bean,實現FactoryBean的介面
第二步:實現介面裡的方法,在實現的方法中定義返回的bean型別
package com.yuge.factoryBean;
import com.yuge.Stu;
import org.springframework.beans.factory.FactoryBean;
public class Mybean implements FactoryBean<Stu> {
@Override
public Stu getObject() throws Exception {
Stu stu = new Stu();
return stu;
}
@Override
public Class<?> getObjectType() {
return null;
}
@Override
public boolean isSingleton() {
return false;
}
}
第三步:配置XML檔案
<bean id="myBean" class="com.yuge.factoryBean.Mybean">
</bean>
測試:
@Test
public void testMyBean(){
ApplicationContext context = new ClassPathXmlApplicationContext("bean3.xml");
Stu stu = context.getBean("myBean",Stu.class);
System.out.println(stu);
}
結果:
7,bean的作用域:
在XML中配置bean時單例項還是多例項:
8,XML的自動裝配
自動裝配:根據指定的裝配規則,(屬性名稱或者屬性型別),Spring自動將匹配的屬性值填入。
演示自動自動裝配:
1,根據名稱裝配
2,根據屬性型別裝配
9,引入外部屬性管理
4.IOC操作Bean(基於註解)
1,spring針對建立物件提供的註解
第一步引入依賴:
第二步:開啟元件掃描
第三步:建立類,在類上新增上註解。
1,@Component,都可以使用改註解建立物件
2,@Service,一般用於業務邏輯層,或者service層
3,@Controller,一般用於Web層
4,@Repository,一般用於Dao層
上面的資格註解,功能都一樣,只是將每個註解用於不同層便於開發人員區別。
2,開啟元件掃面配置的細節配置
3,使用註解出入屬性
1),@Autowired:根據屬性型別自動注入
第一步:使用註解在各個類中建立物件。
第二步:定義物件屬性。在屬性上面新增註解。不需要set方法。
2),@Qualifier:根據屬性名注入
3),@Resource:可以根據屬性名和屬性型別注入
以上三種是注入物件,不是普通型別*
4),@Value:注入普通型別
4,完全註解開發
1),建立配置類,替代XML配置檔案
2),編寫測試類
三,Aop
面向切面,不修改原始碼對功能進行加強。
1,什麼是AOP
對業務的各個邏輯進行隔離,從而使業務之間的邏輯耦合性降低,提高程式碼的可重用性,提高開發效率。
2,AOP的底層原理
1,AOP底層使用動態代理
1,有介面的動態代理,使用JDK的動態代理
建立介面的實現類的代理物件,增強類的方法
2,無介面的動態代理,使用CGLIB動態代理
建立子類的代理物件,增強類的方法
2,使用JDK的動態代理
使用proxy類實現動態代理
程式碼實現:
1,建立介面:
package com.JDK動態代理;
public interface UserDao {
public int add(int a,int b);
public String update(String id);
}
2,建立實現類
package com.JDK動態代理;
public class UserDaoImpl implements UserDao{
@Override
public int add(int a, int b) {
return a+b;
}
@Override
public String update(String id) {
return id;
}
}
3,使用proxy類建立介面的動態代理物件
package com.JDK動態代理;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.security.PublicKey;
import java.security.UnresolvedPermission;
import java.util.Arrays;
public class JDKProxy {
public static void main(String[] args) {
Class[] interfaces = {UserDao.class};
UserDao dao = (UserDao)Proxy.newProxyInstance(UserDaoProxy.class.getClassLoader(), interfaces, new UserDaoProxy(new UserDaoImpl()));
int res = dao.add(1, 2);
System.out.println(res);
}
}
class UserDaoProxy implements InvocationHandler{
//需要將待增強功能的類的物件傳遞到代理類中,並通過構造方法,代理類的構造方法將其例項化
//通過UserDaoProxy建立UserDaoImpl的代理物件
private Object obj;
public UserDaoProxy(Object obj){
this.obj = obj;
}
@Override
/**
*增加邏輯寫在這個方法內
* @ proxy:代理物件
* @ method:需要增強的方法
* @ args:要增強功能的方法需要的引數
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//方法之前
System.out.println("方法之前執行。。。"+method.getName()+"傳遞的引數:"+ Arrays.toString(args));
//被增強方法執行
Object res = method.invoke(obj, args);
//方法之後執行
System.out.println("方法之後執行。。。"+obj);
return res;
}
}
3,AOP中的相關術語
1,連線點:那些方法可以被增強,那些方法就叫連線點。
2,切入點:世界真正被增強的方法就叫切入點。
3,通知(增強):實際被增強的邏輯部分就叫通知或者增強。
通知有多種型別:
4,切面:把通知應用到切入點的動作就叫做切面
## 4,AOP的操作準備
1,Spring框架一般都是基於AspectJ實現AOP操作
AspectJ:不是Spring框架的一部分,獨立於AOP的框架,一般將Spring和AOP框架一起使用進行AOP操作。
2,基於AspectJ實現AOP操作
(1),基於XML配置檔案的AOP操作
(2),基於註解方式實現(使用)
3,在專案的過程中,引入AOP相關的依賴。
4,切入點表示式
(1),切入點表示式作用:知道對哪個類裡面的那個方法進行增強。
(2),語法結構:
execution:([許可權修飾符][返回型別][類全路徑][方法名稱](引數列表))
舉例1:execution(* (返回值可以省略)com.yuge.UserDaoImpl.add(..));
加強com.yuge.UserDaoImpl的add()方法,傳入的引數用..表示,許可權修飾符用*,返回值型別省略。
舉例2:execution( (返回值可以省略)com.yuge.UserDaoImpl.(..)); 對類中的所有方法加強。
舉例3:execution( (返回值可以省略)com.yuge..*(..)); 對包中所有類的所有方法加強
5,AOP操作(AspectJ註解)
1,建立一個類,在類中定義方法,使用註解在類中增強該方法。
package com.AOP註解方式;
public class User {
public void add(){
System.out.println("add...................");
}
}
2,建立一個增強類,編寫增強邏輯
package com.AOP註解方式;
//增強類
public class UserProxy {
//前置通知
public void before(){
System.out.println("before.............");
}
}
3,進行通知的配置
(0)、引入名稱空間
(1),在spring的配置檔案中,開啟註解掃描
<!--開啟註解掃描-->
<context:component-scan base-package="com.AOP註解方式"></context:component-scan>
(2),使用註解建立User物件和UserProxy物件。
(3),在增強類上面新增@Aspect註解
(4),在spring配置檔案中開啟生成代理物件。
<!--開啟AspectJ生成代理物件-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
(5),配置不同型別 的通知
a,在增強類方法上面,新增通知型別。使用切入點表示式配置
package com.AOP註解方式;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
//增強類
@Component
@Aspect //生成代理物件
public class UserProxy {
//前置通知,新增了Before註解,則就會在add()方法之前執行before方法。
@Before("execution(* com.AOP註解方式.User.add(..))")
public void before(){
System.out.println("before.............");
}
//在方法執行之後執行
@After("execution(* com.AOP註解方式.User.add(..))")
public void after(){
System.out.println("after.............");
}
//在方法存在異常時執行
@AfterThrowing("execution(* com.AOP註解方式.User.add(..))")
public void afterThrowing(){
System.out.println("afterThrowing.............");
}
//在方法返回之後執行
@AfterReturning("execution(* com.AOP註解方式.User.add(..))")
public void afterReturning(){
System.out.println("afterReturning.............");
}
//新增環繞方法,在方法執行前後都執行
@Around("execution(* com.AOP註解方式.User.add(..))")
public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("環繞之前.............");
//被增強的方法執行
proceedingJoinPoint.proceed();
System.out.println("環繞之後..............");
}
}
package com.AOP註解方式;
import org.springframework.stereotype.Component;
@Component
public class User {
public void add(){
System.out.println("add...................");
}
}
package com.AOP註解方式;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
@org.junit.Test
public void testAdd(){
//載入上下文配置,讀取xml配置檔案
ApplicationContext context = new ClassPathXmlApplicationContext("bean4.xml");
//獲取物件
User user = (User)context.getBean("user");
user.add();
}
}
<?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:p="http://www.springframework.org/schema/p"
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="com.AOP註解方式"></context:component-scan>
<!--開啟AspectJ生成代理物件-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
<bean id="user" class="com.AOP註解方式.User"></bean>
</beans>
執行結果:
b,總結:
after無論是否存在異常都會執行,afterReturning存在異常時不會執行。
6,AOP操作(AspextJ註解)優化
1,提取相同的切入點
//抽取相同的切入點
@Pointcut(value = "execution(* com.AOP註解方式.User.add(..))")
public void pointCut(){
}
//前置通知,新增了Before註解,則就會在add()方法之前執行before方法。
@Before("pointCut()")
public void before(){
System.out.println("before.............");
}
//在方法執行之後執行
@After("execution(* com.AOP註解方式.User.add(..))")
public void after(){
System.out.println("after.............");
}
2,當有多個增強類對同一個方法進行增強時,設定增強類優先順序
在多個增強類上面設定優先順序使用@Order(整型值)這個註解,整型值越小,優先順序越高
//增強類
@Component
@Aspect //生成代理物件
@Order(3)
public class UserProxy {
//抽取相同的切入點
@Pointcut(value = "execution(* com.AOP註解方式.User.add(..))")
public void pointCut(){
}
@Component
@Aspect
@Order(0)
public class UserProxy2 {
@Before("execution(* com.AOP註解方式.User.add(..))")
public void before(){
System.out.println("UserProxy2增強類先執行。。。。。");
}
}
7,AOP操作(XML配置檔案)
前提在xml中建立增強類和被增強類的物件
8,完全註解開發
四,JdbcTemplate
1,JdbcTempalte的概念
Spring對JDBC進行封裝,使用JdbcTemplate可以方便的對資料庫的操作。
準備工作:
引入依賴:
配置XML建立類注入屬性
2,使用JdbcTemplate模板對資料庫的增刪改查
<context:component-scan base-package="com"/>
<bean id = "dataSource" class="com.druid.DruidDataSource" destroy-method="close">
<property name="url" value="jdbc:mysql://localhost:3306/jdbc_db"/>
<property name="username" value="root"/>
<property name="password" value="3.141592654"/>
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<!--注入dataSource物件-->
<property name="dataSource" ref="dataSource"></property>
</bean>
public interface BookDao {
void add(Book book);
}
@Repository
public class BookDaoImpl implements BookDao {
//注入JdbcTemplate物件
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
public void add(Book book) {
String sql = "insert into book values(?,?,?)";
int update = jdbcTemplate.update(sql, book.getId(), book.getName(), book.getPrice());
System.out.println(update);
}
}
@Service
public class BookService {
//注入BookDao屬性
@Autowired
private BookDao bookDao;
public void insert(Book book){
bookDao.add(book);
}
}
package com.druid;
public class DruidDataSource {
String url;
String password;
String username;
String driverClassName;
public void setUrl(String url) {
this.url = url;
}
public void setPassword(String password) {
this.password = password;
}
public void setUsername(String username) {
this.username = username;
}
public void setDriverClassName(String driverClassName) {
this.driverClassName = driverClassName;
}
private void close() {
}
}
package com.test;
import com.bean.Book;
import com.service.BookService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestJdbcTemplate {
@Test
public void test(){
ApplicationContext context =
new ClassPathXmlApplicationContext("bean4.xml");
BookService bookService = context.getBean("bookService", BookService.class);
Book book = new Book();
book.setId(1);
book.setName("一陽指");
book.setPrice(250);
bookService.insert(book);
}
}
查詢返回某一個值
查詢返回某一個物件
查詢返回一個集合
## 3,使用JdbcTemplate模板對資料庫的批量操作
五,事務操作
1,事務的概念:
回顧:事務是指一組基本的資料操作單元,要麼全部完成操作,要麼全部都不完成操作。
典型事務場景:銀行轉賬
事務的四大特性(ACID):原子性,一致性,隔離性,永續性
2,事務環境的搭建
3,spring事務管理的介紹
1,事務新增到JavaEE的三層體系結構的Service層(業務邏輯層)
2,在Spring事務操作:
1),有兩種方式:程式設計式(在方法中新增程式碼)和宣告式(基於XML或者基於註解方式)
2),宣告式事務管理:底層使用到AOP
3),Spring事務管理相關的API
4,多事務之間事務的傳播行為:
5, ioslation關於事務的隔離級別:
事務的隔離性:多事務的操作之間不會相互影響
如果不考慮隔離:會導致髒讀,幻讀,不可重複讀的問題
解決隔離級別:
配置隔離級別: