Java之Spring5

GitHub:https://github.com/spring-projects/spring-framework

<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd">
 
</beans>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.2.0.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>5.2.0.RELEASE</version>
</dependency>
優點
  1. 開源免費框架
  2. 輕量級 非入侵式框架
  3. 控制反轉(IOC) 面向切面(AOP)
  4. 支持事務的處理 支持框架整合
七大模塊

Spring七大模塊

IOC理論推導
  1. UserDao接口
public interface UserDao {
    void getUser();
}
  1. UserDaoImpl
public class UserDaoImpl implements UserDao {
    @Override
    public void getUser() {
        System.out.println("getUser");
    }
}
public class UserDaoMysqlImpl implements UserDao {
    @Override
    public void getUser() {
        System.out.println("mysql getUser");
    }
}
  1. UserService接口
public interface UserService {
    void getUser();
}
  1. UserServiceImpl
public class UserServiceImpl implements UserService {
    private UserDao userDao;

    // 利用set進行動態實現值的注入
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    @Override
    public void getUser() {
        userDao.getUser();
    }
}
  1. Test
public class MyTest {
    public static void main(String[] args) {
        UserService userService = new UserServiceImpl();
        ((UserServiceImpl) userService).setUserDao(new UserDaoImpl());
        ((UserServiceImpl) userService).setUserDao(new UserDaoMysqlImpl());
        userService.getUser();
    }
}
控制反轉 IOC

獲得依賴對象的方式反轉了,DI(依賴注入)只是控制反轉的一種實現方式

Spring容器在初始化時先讀取配置對象,根據配置文件或元數據創建與組織對象存入容器中,程序使用時再從IOC容器中取出需要的對象。

傳統的應用程序的對象是程序本身控制創建的,使用Spring後,對象是由Spring創建的

HelloSpring
<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--    使用Spring創建對象 在Spring中都稱爲bean-->
    <!--
        類型 變量名 = new 類型();
        Hello hello = new Hello();

        id = 變量名
        class = new 的對象
        property 相當於給對象的屬性設置值
    -->
    <bean id="hello" class="com.wang.pojo.Hello">
        <property name="str" value="string"></property>
    </bean>
</beans>
public class Hello {
    private String str;

    public String getStr() {
        return str;
    }

    public void setStr(String str) {
        this.str = str;
    }

    @Override
    public String toString() {
        return "Hello{" +
                "str='" + str + '\'' +
                '}';
    }
}
public class MyTest {
    public static void main(String[] args) {
//        獲取Spring的上下文對象
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        // 我們的對象都在Spring中管理了 要使用的時候在Spring取就可以
        Hello hello = (Hello) context.getBean("hello");
        System.out.println(hello.toString());
    }
}
IOC創建對象的方式
  1. 使用無參構造創建對象 默認
    <bean id="user" class="com.wang.pojo.User">
        <property name="name" value="英豪"></property>
    </bean>
  1. 假設我們要使用有參構造創建對象
    <bean id="user" class="com.wang.pojo.User">
        <!--        第一種 下標賦值-->
        <constructor-arg index="0" value="英豪"></constructor-arg>
    </bean>
    <bean id="user" class="com.wang.pojo.User">
        <!--        第二種 通過類型創建 不建議使用-->
        <constructor-arg type="java.lang.String" value="英豪"></constructor-arg>
    </bean>
    <bean id="user" class="com.wang.pojo.User">
        <!--        第三種 通過參數名賦值-->
        <constructor-arg name="name" value="英豪"></constructor-arg>
    </bean>

總結:在配置文件加載的時候,容器中管理的bean已經初始化了

Spring的配置

Alias
    <!--    添加別名 也可以用別名獲取到對象-->
    <alias name="user" alias="user2"></alias>
Bean的配置
    <!--
    id: bean的唯一標識符
    class:bean對象所對應的全限定名:包名+類型
    name:也是別名,name更高級,可以同時取多個別名(逗號 空格 分號等都可以分隔)
    scope="singleton" 單例 默認是單例 還可以是prototype session request
    -->
    <bean id="user" class="com.wang.pojo.User" name="user3,user4,user5" scope="singleton">
        <constructor-arg name="name" value="英豪"></constructor-arg>
    </bean>
import

一般是用於團隊開發使用,可以將多個配置文件導入合併爲一個

<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd">
    <import resource="beans.xml"></import>
    <import resource="beans2.xml"></import>
</beans>

DI 依賴注入

構造器注入

前面已經說過了

set方式注入【重點】 需要無參構造器

  • 依賴注入 Set注入
    • 依賴:bean對象的創建依賴於容器
    • 注入:bean對象中的所有屬性,由容器注入
public class Student {
    private String name;
    private Address address;
    private String[] books;
    private List<String> hobbies;
    private Map<String, String> card;
    private Set<String> games;
    private String wife;
    private Properties info;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }

    public String[] getBooks() {
        return books;
    }

    public void setBooks(String[] books) {
        this.books = books;
    }

    public List<String> getHobbies() {
        return hobbies;
    }

    public void setHobbies(List<String> hobbies) {
        this.hobbies = hobbies;
    }

    public Map<String, String> getCard() {
        return card;
    }

    public void setCard(Map<String, String> card) {
        this.card = card;
    }

    public Set<String> getGames() {
        return games;
    }

    public void setGames(Set<String> games) {
        this.games = games;
    }

    public String getWife() {
        return wife;
    }

    public void setWife(String wife) {
        this.wife = wife;
    }

    public Properties getInfo() {
        return info;
    }

    public void setInfo(Properties info) {
        this.info = info;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", address=" + address +
                ", books=" + Arrays.toString(books) +
                ", hobbies=" + hobbies +
                ", card=" + card +
                ", games=" + games +
                ", wife='" + wife + '\'' +
                ", info=" + info +
                '}';
    }
}
public class Address {
    private String address;

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "Address{" +
                "address='" + address + '\'' +
                '}';
    }
}
<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="address" class="com.wang.pojo.Address">
        <property name="address" value="遼寧"></property>
    </bean>

    <bean id="student" class="com.wang.pojo.Student">
        <property name="name" value="英豪"></property>
        <property name="address" ref="address"></property>
        <property name="books">
            <array>
                <value>紅樓夢</value>
                <value>西遊記</value>
                <value>水滸傳</value>
                <value>三國演義</value>
            </array>
        </property>
        <property name="hobbies">
            <list>
                <value>聽歌</value>
                <value>代碼</value>
                <value>電影</value>
            </list>
        </property>
        <property name="card">
            <map>
                <entry key="身份證" value="111111111"></entry>
                <entry key="銀行卡" value="2222222222"></entry>
            </map>
        </property>
        <property name="games">
            <set>
                <value>LOL</value>
                <value>COC</value>
                <value>BOB</value>
            </set>
        </property>
        <property name="wife">
            <null></null>
        </property>
        <property name="info">
            <props>
                <prop key="學號">21022518</prop>
                <prop key="性別"></prop>
            </props>
        </property>
    </bean>
</beans>
public class MyTest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        Student student = (Student) context.getBean("student");
        System.out.println(student);
        // Student{
        //  name='英豪',
        //  address=Address{address='遼寧'},
        // books=[紅樓夢, 西遊記, 水滸傳, 三國演義],
        // hobbies=[聽歌, 代碼, 電影],
        // card={
        //  身份證=111111111,
        //  銀行卡=2222222222},
        // games=[LOL, COC, BOB],
        // wife='null',
        // info={
        //  學號=21022518,
        //  性別=男}}
    }
}
拓展方式注入

P命名空間注入
C命名空間注入

<?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:c="http://www.springframework.org/schema/c"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--    p命名空間注入 可以直接注入屬性的值 需要導入xml約束 xmlns:p="http://www.springframework.org/schema/p"-->
    <bean id="user" class="com.wang.pojo.User" p:name="英豪" p:age="18"></bean>

    <!--    c命名空間注入通過有參構造器注入 需要導入xml約束 xmlns:c="http://www.springframework.org/schema/c"-->
    <bean id="user2" class="com.wang.pojo.User" c:age="18" c:name="英豪"></bean>

</beans>

bean的作用域

在這裏插入圖片描述

The Singleton Scope(默認)

單例

<bean id="accountService" class="com.something.DefaultAccountService" scope="singleton"/>
The Prototype Scope 原型模式

每次從容器中get的時候都會新建一個新對象
在這裏插入圖片描述

<bean id="accountService" class="com.something.DefaultAccountService" scope="prototype"/>
Request, Session, Application, and WebSocket Scopes

web開發中使用

Bean的自動裝配

  • 自動裝配是Spring滿足bean依賴的一種方式
  • Spring會在上下文中自動尋找,並自動給bean裝配屬性

在Spring中有三種裝配方式:

  1. xml中顯示配置
  2. 在java中顯示配置
  3. 隱式自動裝配
public class Cat {
    public void shout() {
        System.out.println("miao");
    }
}
public class Dog {
    public void shout() {
        System.out.println("wang");
    }
}
public class People {
    private Cat cat;
    private Dog dog;
    private String name;

    public Cat getCat() {
        return cat;
    }

    public void setCat(Cat cat) {
        this.cat = cat;
    }

    public Dog getDog() {
        return dog;
    }

    public void setDog(Dog dog) {
        this.dog = dog;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "People{" +
                "cat=" + cat +
                ", dog=" + dog +
                ", name='" + name + '\'' +
                '}';
    }
}
<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="cat" class="com.wang.pojo.Cat"></bean>
    <bean id="dog" class="com.wang.pojo.Dog"></bean>
    <!--    <bean id="people" class="com.wang.pojo.People">-->
    <!--        <property name="name" value="英豪"></property>-->
    <!--        <property name="cat" ref="cat"></property>-->
    <!--        <property name="dog" ref="dog"></property>-->
    <!--    </bean>-->

    <!--    注入成功 byName會在容器上下文中查找 和自己對象set方法後面的值對應的bean id
    上面Dog bean id改成 dog2222的話就會注入失敗
    -->
    <!--    <bean id="people" class="com.wang.pojo.People" autowire="byName">-->
    <!--        <property name="name" value="英豪"></property>-->
    <!--    </bean>-->

    <!--    注入成功 byType會在容器上下文中查找 和自己對象屬性類型對應相同的bean 但是如果存在兩個類型相同的bean 比如 dog1 dog2 就會失敗-->
    <bean id="people" class="com.wang.pojo.People" autowire="byType">
        <property name="name" value="英豪"></property>
    </bean>
</beans>
ByName裝配
 <!--    注入成功 byName會在容器上下文中查找 和自己對象set方法後面的值對應的bean id
    上面Dog bean id改成 dog2222的話就會注入失敗
    -->
    <!--    <bean id="people" class="com.wang.pojo.People" autowire="byName">-->
    <!--        <property name="name" value="英豪"></property>-->
    <!--    </bean>-->
ByType裝配
    <!--    注入成功 byType會在容器上下文中查找 和自己對象屬性類型對應相同的bean 但是如果存在兩個類型相同的bean 比如 dog1 dog2 就會失敗-->
    <bean id="people" class="com.wang.pojo.People" autowire="byType">
        <property name="name" value="英豪"></property>
    </bean>

小結:

  • byName需要保證所有bean的id唯一,並且這個bean需要和自動注入的屬性的set方法的值一致
  • byType的時候,需要保證所有bean的class唯一,並且這個bean和自動注入的屬性的類型一致

使用註解自動裝配

使用註解須知:

  1. 導入約束 context約束 xmlns:context=“http://www.springframework.org/schema/context”
  2. 配置註解的約束 context:annotation-config/
<?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"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd">

    <context:annotation-config/>

</beans>

@Autowired
直接在屬性上使用即可 也可以在set使用
使用Autowired可以不編寫set方法,前提是自動裝配的屬性在IOC容器中存在

Autowired默認先按照byType裝配 後byName
實測一:這個可以裝配 說明是按照byType裝配

    <bean id="cat" class="com.wang.pojo.Cat"></bean>
    <bean id="dog23" class="com.wang.pojo.Dog"></bean>
    <bean id="people" class="com.wang.pojo.People"></bean>

實測二:這個可以裝配 說明是按照byName裝配

    <bean id="cat" class="com.wang.pojo.Cat"></bean>
    <bean id="dog23" class="com.wang.pojo.Dog"></bean>
    <bean id="dog" class="com.wang.pojo.Dog"></bean>
    <bean id="people" class="com.wang.pojo.People"></bean>

實測三:這個不可以裝配

    <bean id="cat" class="com.wang.pojo.Cat"></bean>
    <bean id="dog23" class="com.wang.pojo.Dog"></bean>
    <bean id="dog333" class="com.wang.pojo.Dog"></bean>
    <bean id="people" class="com.wang.pojo.People"></bean>

@Nullable 字段標記了這個註解 說明這個字段可以爲null
如果Autowired自動裝配環境比較複雜,可以使用@Qualifier(value = “dog23”)配置使用,byName指定唯一注入

    @Autowired
    @Qualifier(value = "dog23")
    private Dog dog;

@Resource java自帶

使用註解開發

在Spring4之後,要使用註解開發,必須導入AOP的包
在這裏插入圖片描述
使用註解需要導入context約束,增加註解的支持

<?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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd">

    <context:annotation-config/>
</beans>
  1. bean
  2. 屬性如何注入
//等價於 <bean id = "user" class="com.wang.pojo.User"/>
@Component
public class User {
    @Value("英豪")
    public String name;
}
  1. 衍生的註解
    @Component有幾個衍生註解,我們在web開發中,會按照mvc三層架構分層
  • dao 【@Repository】
  • service 【@Service】
  • controller 【@Controller】
    這四個註解功能都是一樣的,都是代表將某個類註冊到Spring中,裝配Bean,需要配置掃描
  1. 自動裝配置
    @Autowired
    @Qualifier(
    @Resource
  2. 作用域
    @Scope(value = “prototype”)
  3. 小結
    xml與註解
  • xml更加萬能,適用於任何場合 維護方便
  • 註解 不是自己的類使用不了 維護相對複雜

xml與註解的最佳實踐:

  • xml管理bean
  • 註解只負責完成屬性注入

使用Java的方式配置Spring

我們現在完全不使用Spring的xml配置了,全權交給Java來做
JavaConfig是Spring的一個子項目,在Spring4之後成爲了一個核心功能

AOP

代理模式:AOP的底層
代理模式分類:

  • 靜態代理
  • 動態代理
靜態代理

角色分析:

  • 抽象角色:一般會使用接口或者抽象類來解決
  • 真實角色:被代理的角色
  • 代理角色:代理真實角色,代理真實角色後,我們一般會做一些附屬操作
  • 客戶:訪問代理對象的人

實現步驟:

  1. 接口
public interface Rent {
    public void rent();
}
  1. 真實角色
public class Host implements Rent {
    @Override
    public void rent() {
        System.out.println("房東出租房子");
    }
}
  1. 代理角色
public class Proxy implements Rent {
    private Host host;

    public Proxy() {
    }

    public Proxy(Host host) {
        this.host = host;
    }

    @Override
    public void rent() {
        seeHouse();
        host.rent();
        fare();
    }

    public void seeHouse() {
        System.out.println("seeHouse");
    }

    public void fare() {
        System.out.println("fare");
    }
}
  1. 客戶端訪問
public class Client {
    public static void main(String[] args) {
        Host host = new Host();
        host.rent();
    }
}

代理模式的好處:

  • 可以使真實角色的操作更加純粹 不用去關注一些公共業務
  • 公共業務交給代理角色 實現業務分工
  • 公共業務發生擴展時 方便集中管理
    缺點:
  • 一個真實角色產生一個代理角色 代碼量翻倍
public interface UserService {
    public void add();

    public void delete();

    public void update();

    public void query();
}

public class UserServiceImpl implements UserService {
    @Override
    public void add() {
        System.out.println("add");
    }

    @Override
    public void delete() {
        System.out.println("delete");
    }

    @Override
    public void update() {
        System.out.println("update");
    }

    @Override
    public void query() {
        System.out.println("query");
    }
}

public class UserServiceProxy implements UserService {

    private UserServiceImpl userService;

    public void setUserService(UserServiceImpl userService) {
        this.userService = userService;
    }

    @Override
    public void add() {
        log("add");
        userService.add();
    }

    @Override
    public void delete() {
        log("delete");
        userService.delete();
    }

    @Override
    public void update() {
        log("update");
        userService.update();
    }

    @Override
    public void query() {
        log("query");
        userService.query();
    }

    public void log(String msg){
        System.out.println(msg);
    }
}

public class Client {
    public static void main(String[] args) {
        UserServiceImpl userService = new UserServiceImpl();
        UserServiceProxy userServiceProxy = new UserServiceProxy();
        userServiceProxy.setUserService(userService);
        userServiceProxy.add();
    }
}
動態代理
  • 動態代理和靜態代理的角色一樣
  • 動態代理的代理類是動態生成的,不是直接寫好的
  • 動態代理分爲兩大類:基於接口的動態代理 基於類的動態代理
    • 基於接口——JDK動態代理
    • 基於類——cglib
    • java字節碼實現:javassist

需要了解兩個類:Proxy 代理 InvocationHandler 調用處理程序

Proxy 生成動態代理類

    public Object getProxy() {
        return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }

InvocationHandler 調用處理程序並返回結果

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 動態代理的本質 就是使用反射機制實現
        Object result = method.invoke(target, args);
        return result;
    }

動態代理的好處:

  • 可以使真實角色的操作更加純粹 不用去關注一些公共業務
  • 公共業務交給代理角色 實現業務分工
  • 公共業務發生擴展時 方便集中管理
  • 一個動態代理類代理的是一個接口 一般就是對應的一類業務
  • 一個動態代理類可以代理多個類 只要是實現了同一個接口即可
/**
 * @Description: 用這個類動態生成代理類
 * @Author: wangyinghao
 * @Date: 2020-06-09 10:26
 **/
public class ProxyInvocationHandler implements InvocationHandler {

    //被代理的接口
    private Object target;

    public void setTarget(Object target) {
        this.target = target;
    }

    public Object getProxy() {
        return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }

    //處理代理實例並返回結果
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        log(method.getName());
        // 動態代理的本質 就是使用反射機制實現
        Object result = method.invoke(target, args);
        return result;
    }

    public void log(String msg) {
        System.out.println(msg);
    }
}
public class Client {
    public static void main(String[] args) {
        UserServiceImpl userService = new UserServiceImpl();
        //代理角色 現在沒有
        ProxyInvocationHandler pih = new ProxyInvocationHandler();
        pih.setTarget(userService);
        UserService proxy = (UserService) pih.getProxy();

        proxy.add();
    }
}

AOP

什麼是AOP:

面向切面編程,通過預編譯方式和運行期動態代理實現程序功能的統一維護的一種技術。AOP是OOP的延續,是軟件開發中的一個熱點,也是Spring框架中的一個重要內容,是函數式編程的一種衍生範型。利用AOP可以對業務邏輯的各個部分隔離,從而使得業務邏輯各個部分之間的耦合度降低,提高程序的可重用性,同時提高了開發的效率。

使用Spring實現AOP

導入依賴包

        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.2</version>
        </dependency>

方式一:使用Spring的API接口

public interface UserService {
    public void add();
    public void delete();
    public void update();
    public void select();
}

public class UserServiceImpl implements UserService {
    @Override
    public void add() {
        System.out.println("增加了一個用戶");
    }

    @Override
    public void delete() {
        System.out.println("刪除了一個用戶");
    }

    @Override
    public void update() {
        System.out.println("修改了一個用戶");
    }

    @Override
    public void select() {
        System.out.println("查詢了一個用戶");
    }
}

public class AfterLog implements AfterReturningAdvice {

    // returnValue 返回值
    @Override
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
        System.out.println("執行了" + method.getName() + "方法,返回結果爲" + returnValue);
    }
}

public class Log implements MethodBeforeAdvice {

    // method 要執行的目標對象的方法
    // objects 參數
    // o 目標對象
    @Override
    public void before(Method method, Object[] objects, Object o) throws Throwable {
        System.out.println(o.getClass().getName() + "的" + method.getName() + "被執行了");
    }
}
<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd">
    <!--    註冊bean-->
    <bean id="userService" class="com.wang.service.UserServiceImpl"></bean>
    <bean id="log" class="com.wang.log.Log"></bean>
    <bean id="afterLog" class="com.wang.log.AfterLog"></bean>

    <!--    配置AOP 需要導入aop約束-->
    <aop:config>
        <!--切入點 expression 表達式 execution 要執行的位置-->
        <aop:pointcut id="pointcut" expression="execution(* com.wang.service.UserServiceImpl.*(..))"/>
        <!--        執行環繞增強-->
        <aop:advisor advice-ref="log" pointcut-ref="pointcut"></aop:advisor>
        <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"></aop:advisor>
    </aop:config>
</beans>
public class MyTest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserService userService = context.getBean("userService", UserService.class);
        userService.add();
    }
}

方式二:自定義類實現AOP

public class DiyPointCut {
    public void before(){
        System.out.println("=====方法執行前=====");
    }

    public void after(){
        System.out.println("=====方法執行後=====");
    }
}
<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd">
    <!--    註冊bean-->
    <bean id="userService" class="com.wang.service.UserServiceImpl"></bean>
    <bean id="log" class="com.wang.log.Log"></bean>
    <bean id="afterLog" class="com.wang.log.AfterLog"></bean>

    <!--    方式一 使用原生Spring API接口-->
    <!--    配置AOP 需要導入aop約束-->
    <!--    <aop:config>-->
    <!--        &lt;!&ndash;切入點 expression 表達式 execution 要執行的位置&ndash;&gt;-->
    <!--        <aop:pointcut id="pointcut" expression="execution(* com.wang.service.UserServiceImpl.*(..))"/>-->
    <!--        &lt;!&ndash;        執行環繞增強&ndash;&gt;-->
    <!--        <aop:advisor advice-ref="log" pointcut-ref="pointcut"></aop:advisor>-->
    <!--        <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"></aop:advisor>-->
    <!--    </aop:config>-->

    <!--    方式二 自定義類-->
    <bean id="diy" class="com.wang.diy.DiyPointCut"></bean>
    <aop:config>
        <aop:aspect ref="diy">
            <!--            切入點-->
            <aop:pointcut id="point" expression="execution(* com.wang.service.UserServiceImpl.*(..))"/>
            <!--            通知-->
            <aop:before method="before" pointcut-ref="point"></aop:before>
            <aop:after method="after" pointcut-ref="point"></aop:after>
        </aop:aspect>
    </aop:config>
</beans>

方式三:使用註解實現

/**
 * @Description: 使用註解方式實現AOP
 * @Author: wangyinghao
 * @Date: 2020-06-10 10:52
 **/
@Aspect // 標註這個類是個切面
public class AnnotationPointCut {
    @Before("execution(* com.wang.service.UserServiceImpl.*(..))")
    public void before() {
        System.out.println("=====方法執行前=====");
    }

    @After("execution(* com.wang.service.UserServiceImpl.*(..))")
    public void after() {
        System.out.println("=====方法執行後=====");
    }
}
<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd">
    <!--    註冊bean-->
    <bean id="userService" class="com.wang.service.UserServiceImpl"></bean>
    <bean id="log" class="com.wang.log.Log"></bean>
    <bean id="afterLog" class="com.wang.log.AfterLog"></bean>

    <!--    方式一 使用原生Spring API接口-->
    <!--    配置AOP 需要導入aop約束-->
    <!--    <aop:config>-->
    <!--        &lt;!&ndash;切入點 expression 表達式 execution 要執行的位置&ndash;&gt;-->
    <!--        <aop:pointcut id="pointcut" expression="execution(* com.wang.service.UserServiceImpl.*(..))"/>-->
    <!--        &lt;!&ndash;        執行環繞增強&ndash;&gt;-->
    <!--        <aop:advisor advice-ref="log" pointcut-ref="pointcut"></aop:advisor>-->
    <!--        <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"></aop:advisor>-->
    <!--    </aop:config>-->

    <!--    方式二 自定義類-->
    <!--    <bean id="diy" class="com.wang.diy.DiyPointCut"></bean>-->
    <!--    <aop:config>-->
    <!--        <aop:aspect ref="diy">-->
    <!--            &lt;!&ndash;            切入點&ndash;&gt;-->
    <!--            <aop:pointcut id="point" expression="execution(* com.wang.service.UserServiceImpl.*(..))"/>-->
    <!--            &lt;!&ndash;            通知&ndash;&gt;-->
    <!--            <aop:before method="before" pointcut-ref="point"></aop:before>-->
    <!--            <aop:after method="after" pointcut-ref="point"></aop:after>-->
    <!--        </aop:aspect>-->
    <!--    </aop:config>-->

    <!--    方式三-->
    <bean id="annotationPointCut" class="com.wang.diy.AnnotationPointCut"></bean>

    <!--    開啓註解支持-->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>

整合Mybatis

步驟:

  1. 導入相關jar包
    • junit
    • mybatis
    • mysql數據庫
    • spring相關
    • aop
    • mybatis-spring
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>kuangshen-spring-study</artifactId>
        <groupId>org.example</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>spring-10-mybatis</artifactId>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.48</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.2</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.2.0.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.2.0.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.2</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>2.0.5</version>
        </dependency>
    </dependencies>
</project>
  1. 編寫配置文件
  2. 測試
  • 編寫數據源配置
    <!--    DataSource 使用Spring數據源替換Mybatis的配置 c3p0 dbcp druid-->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
        <property name="url"
                  value="jdbc:mysql://aliyun:3306/mybatis?useUnicode=true&amp;characterEncoding=UTF-8"></property>
        <property name="username" value="root"></property>
        <property name="password" value="Lndlwyh919190."></property>
    </bean>
  • sqlSessionFactory
    <!--    sqlSessionFactory-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"></property>
        <!--        綁定mybatis配置文件-->
        <property name="configLocation" value="classpath:mybatis-config.xml"></property>
        <property name="mapperLocations" value="classpath:com/wang/mapper/*.xml"></property>
    </bean>
  • sqlSessionTemplate
    <!--    sqlSessionTemplate就是我們使用的sqlSession-->
    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
        <!--        只能用構造器注入 因爲SqlSessionTemplate沒set方法-->
        <constructor-arg index="0" ref="sqlSessionFactory"></constructor-arg>
    </bean>
  • 給接口加實現類
public interface UserMapper {

    List<User> selectUser();
}
public class UserMapperImpl implements UserMapper {

    // 我們所有操作都是用sqlSessionTemplate執行
    private SqlSessionTemplate sqlSession;

    public void setSqlSession(SqlSessionTemplate sqlSession) {
        this.sqlSession = sqlSession;
    }

    @Override
    public List<User> selectUser() {
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        return mapper.selectUser();

    }
}
<mapper namespace="com.wang.mapper.UserMapper">
    <select id="selectUser" resultType="User">
        select * from mybatis.user;
    </select>
</mapper>
    <bean id="userMapper" class="com.wang.mapper.UserMapperImpl">
        <property name="sqlSession" ref="sqlSession"></property>
    </bean>
  • 測試
public class MyTest {
    @Test
    public void test() {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserMapper userMapper = context.getBean("userMapper", UserMapper.class);
        for (User user : userMapper.selectUser()) {
            System.out.println(user.toString());
        }
    }
}

聲明式事務

事務的ACID原則

  • 原子性
  • 一致性
  • 隔離性
  • 持久性

Spring中的事務

  • 聲明式事務 AOP
  • 編程式事務:需要在代碼中 進行事務管理
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章