Sping study notes (with examples, super detailed)

Table of contents

1. Let’s talk about what is Spring first

1.1 The dependencies that need to be imported to write Spring code: (which contains many jar packages)

 2. Inversion of Control (IOC) Theoretical Derivation

2.1 Get Spring's context object in Test

2.2 Dependency Injection

2.3 Extension: C tag and P tag injection

3. Inversion of Control

4. The way IOC creates objects

4.1 Subscript assignment, but need to create a constructor with parameters

4.2 Creation by type is deprecated

4.3 Set directly through parameters

5. Database connection pool

6.Bean scope

6.1 Singleton mode: (Spring default mechanism)

6.2 Prototype pattern

6.3. Other requests, sessions, applications

7.Bean automatic assembly

7.1 Using annotations to realize automatic assembly

7.1.1@Autowired

7.1.2 Import constraints

7.1.3 Bean implementation

7.1.4 Property Injection

7.2 Configuration annotation support

7.2.1 Difference between @Autowired and @Resource

7.3 Comparison of XML and Annotations

8. Proxy mode

8.1 What AOP is used for

8.2 Static proxy

8.3 In-depth understanding of static proxy

9. Dynamic proxy

9.1 Examples

9.2 Deeper understanding of dynamic proxies

9.3 Summary of Proxy Mode

10. Understanding reflection

11.AOP

11.1 What is AOP

11.2 The role of Aop in Spring 

 11.2.1 Two proxy methods of Spring AOP

11.3 Start with the topic, first guide the package

11.4 Specifically divided into three ways

11.4.1 The first way: use the original SpringAPI interface

11.4.2 Method 2: Customize the class to implement Aop

11.4.3 Method 3 Use annotations to implement

11.5 AOP "Heart Bleeding" Summary

12. Declarative transactions 

12.1 Four attributes of transactions

12.2 Transaction Management in Spring 

12.2.1 Transaction Manager 

12.3 Spring transaction propagation features 

12.4 Constrained import of header files 

12.5 Case 

13. Periodic self-summarization


1. Let’s talk about what is Spring first


    1.Spirng is a free open source container (framework);
    2.Spring is a lightweight, non-invasive framework;
    3. Inversion of Control (IOC), Aspect-Oriented Programming (AOP);
    4. Support transactions Processing, support for framework integration!



1.1 The dependencies that need to be imported to write Spring code: (which contains many jar packages)

地址:<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>6.0.2</version>
</dependency>

 
2. Inversion of Control (IOC) Theoretical Derivation

  • In essence, it solves the need for programmers to manage the creation of objects , and reduces the coupling of the system .
  • The program passively provides the interface, and the initiative is in the hands of the user. It only needs to obtain the user's operation, and then call the corresponding method
  • Inversion of control is a way to generate or obtain specific objects through description (xml or annotation) and through a third party.
  • It is the IOC container that implements inversion of control in Spring, and its implementation method is dependency injection (DI)

2.1 Get Spring's context object in Test

ApplicationContext context = new ClassPathXmlApplicationContext("xml文件");

        Then go to .get whoever you need

2.2 Dependency Injection

Example:

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 + '\'' +
                '}';
    }
}
//对应不同的注入方式
public class Student {
    private String name;
    private Address address;
    private String[] books;
    private List<String> hobbys;
    private Map<String,String> card;
    private Set<String> games;
    private String wife;
    private Properties info;

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", address=" + address.toString() +
                ", books=" + Arrays.toString(books) +
                ", hobbys=" + hobbys +
                ", card=" + card +
                ", games=" + games +
                ", wife='" + wife + '\'' +
                ", info=" + 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> getHobbys() {
        return hobbys;
    }

    public void setHobbys(List<String> hobbys) {
        this.hobbys = hobbys;
    }

    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;
    }
}

beans.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:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util https://www.springframework.org/schema/util/spring-util.xsd">
    <bean id="address" class="com.gcx.pojo.Address">
        <property name="address" value="青岛"/>
    </bean>
    <bean id="student" class="com.gcx.pojo.Student">
<!--        第一种普通值注入 value-->
        <property name="name" value="gcx"/>
<!--        第二种注入bean注入, ref-->
        <property name="address" ref="address"/>
<!--        数组注入-->
        <property name="books">
            <array>
                <value>红楼梦</value>
                <value>西游记</value>
                <value>水浒传</value>
                <value>三国演义</value>
            </array>
        </property>
<!--        List-->
        <property name="hobbys">
            <list>
                <value>听歌</value>
                <value>看电影</value>
                <value>玩游戏</value>
            </list>
        </property>
<!--        map-->
        <property name="card">
            <map>
                <entry key="身份证" value="111111111111111111"/>
                <entry key="银行卡" value="684546554466455545"/>
            </map>
        </property>
<!--        set-->
        <property name="games">
            <set>
                <value>LOL</value>
                <value>COC</value>
                <value>BOB</value>
            </set>
        </property>
<!--        null-->
        <property name="wife">
            <null/>
        </property>
<!--        Properties-->
        <property name="info">
            <props>
                <prop key="studyId">78945621</prop>
                <prop key="phone">20221206</prop>
                <prop key="姓名">小明</prop>
            </props>
        </property>
    </bean>


</beans>

 Test test

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.toString());
    }

2.3 Extension: C tag and P tag injection

public class User {
    private String name;
    private int age;

    public User() {
    }

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

UserBean.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:util="http://www.springframework.org/schema/util"
       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 http://www.springframework.org/schema/util https://www.springframework.org/schema/util/spring-util.xsd">
<!--需要先导入约束(第4 5行)-->
    <!--    P命名空间注入-->
    <bean id="User" class="com.gcx.pojo.User" p:name="gcx" p:age="18"/>
<!--C命名空间注入 通过有参无参注入-->
    <bean id="user2" class="com.gcx.pojo.User" c:age="18" c:name="cxg"/>
</beans>

Test test:

@Test
    public void test(){
        ApplicationContext context = new ClassPathXmlApplicationContext("UserBean.xml");
        User user = (User) context.getBean("user2");//测试P标签对应beanid为user
        System.out.println(user);
    }


3. Inversion of Control


    Control: who controls the creation of objects, the objects of traditional applications are created by the program itself; after using Spring, the objects are created by Spring. Inversion: the
    program itself does not create objects, but becomes a passive receiving object .
    Dependency injection: It is to use the set method to inject.
    IOC is a programming idea, which changes from active programming to passive reception.


To achieve different operations, you only need to modify it in the XML configuration file. The so-called IOC means that the object is created, managed and assembled by Spring! 

4. The way IOC creates objects


Use no-argument constructor

<property name="name" value="123"/>


4.1 Subscript assignment, but need to create a constructor with parameters
 

<constructor-arg index="0" value="456"/>


4.2 Creation by type is deprecated

<constructor-arg type="java.lang.String" value="gcx"/>


4.3 Set directly through parameters

<bean id="user" class="com.gcx.User">
        <constructor-arg name="name" value="gcx"/>
</bean>

5. Database connection pool


Pooling technology: Prepare some pre-resources, and link to the pre-prepared
connections when you come over. Minimum number of connections: Set according to the number of commonly used connections.
Maximum number of connections: Set the maximum number of connections. When the number of connections exceeds the maximum number of connections, it will wait in line
Waiting timeout: When the waiting time exceeds the queuing waiting time, it will automatically exit the waiting time and prompt an error.

Write a connection pool and implement an interface DataSource
common data pool:

  • DBCP (import jar package)
  • c3p0 (import jar package)
  • Druid: Alibaba

After using these database connection pools, there is no need to write database code;
no matter what data source is used, the essence is the same: the Datasource interface will not change, and the method will not change

6.Bean scope


6.1 Singleton mode: (Spring default mechanism)

<!--<bean id="accountService" class="com.something.DefaultAccountService"/>
(singleton scope is the default) -->
<bean id="accountService" class="com.something.DefaultAccountService" scope="singleton"/>


6.2 Prototype pattern

Disadvantage: Every time you get from the container, a new object will be generated (wasting resources)!
 

<bean id="accountService" class="com.something.DefaultAccountService" scope="prototype"/>


6.3. Other requests, sessions, applications

这些只能在web开发中使用到。
官网原话:The request, session, application, and websocket scopes are available only if you use a web-aware Spring ApplicationContext implementation (such as XmlWebApplicationContext). 
If you use these scopes with regular Spring IoC containers, 
such as the ClassPathXmlApplicationContext, 
an IllegalStateException that complains about an unknown bean scope is thrown.

7.Bean automatic assembly


Three automatic assembly methods:

                                  1. Display configuration in xml
                                  2. Display configuration in java
                                  3. Implicit automatic assembly bean [important] (byName, byType)


7.1 Using annotations to realize automatic assembly

1. The jar package of aop needs to be imported (check the maven plugin)

2. @Autowired (commonly used), @Resource

7.1.1@Autowired

Example:

public class Cat {
    public void shout(){
        System.out.println("miao");
    }
}
public class Dog {
    public void shout(){
        System.out.println("wang");
    }
}
public class People {
//    如果显示定义了Autowired属性的required为false,说明这个属性可以为null,否则不允许为空;
//    @Autowired(required = false)
    @Autowired
    @Qualifier(value = "cat11")
//    @Qualifier(value = "beanid")当自动装配无法通过一个注解完成时,用来指定一个唯一的bean对象注入
    private Cat cat;
    @Autowired
    @Qualifier(value = "dog11")
    private Dog dog;
    private String name;

    @Override
    public String toString() {
        return "People{" +
                "cat=" + cat +
                ", dog=" + dog +
                ", name='" + 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;
    }
}

 beans.xml (non-standard)

<?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/>
<!--    使用Autowired可以不用set方法,前提是自动装配的属性在IOC容器中存在且符合名字byName-->
        <bean id="cat" class="com.gcx.pojo.Cat"/>
        <bean id="cat11" class="com.gcx.pojo.Cat"/>
        <bean id="dog" class="com.gcx.pojo.Dog"/>
        <bean id="dog11" class="com.gcx.pojo.Dog"/>
<!--    自动装配:autowire    byName:会自动在容器上下文中查找,和自己对象set方法后面的值对应的beanid(必须对应相同,所有bean的id唯一)
                    byType:会自动在容器上下文中查找,和自己对象属性类型对应相同bean(必须保证所有bean的class全局唯一)-->
    <bean id="people" class="com.gcx.pojo.People">
        <property name="name" value="gcx"/>
<!--        <property name="cat" ref="cat"/>-->
<!--        <property name="dog" ref="dog"/>-->
     </bean>
<!--    开启注解支持-->

</beans>

Test test

public class Mytest {
    @Test
    public void test(){
        ApplicationContext Context = new ClassPathXmlApplicationContext("beans.xml");
        People people = (People) Context.getBean("people");
        people.getDog().shout();
        people.getCat().shout();
    }
}


7.1.2 Import constraints

xmlns:context="http://www.springframework.org/schema/context"
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd


7.1.3 Bean implementation


Specify the annotation scanning package to configure which packages are scanned for annotations

<context:component-scan base-package="com.gcx"/>


7.1.4 Property Injection


    (1) It is not necessary to provide a set method, but directly add @value("value");
    (2) If a set method is provided, add @value("value"); to the set method;


7.2 Configuration annotation support

<context:annotation-config/> //若使用注解就必须开启,否则注入为空


If the environment for automatic assembly of @Autowired annotations is more complicated, and automatic assembly cannot be completed through an annotation [@Autowired], we can use @Qualifier(value = "xxx") to configure the use of @Autowired and specify a unique bean object injection!


7.2.1 Difference between @Autowired and @Resource


1. Both are used for automatic assembly, and can be placed on the attribute field
2. @Autowired is implemented by the method of byType
3. @Resource is the method of byName by default. If the same name cannot be found, it will be passed byType accomplish!
If neither of them can be found, an error will be reported!
4. The order of execution is different: @Autowired is implemented by the method of byType, and @Resource is implemented by the method of byName by default.

7.3 Comparison of XML and Annotations


1.XML can be applied to any scene, with clear structure and easy maintenance.
2. The annotations are not provided by the class and cannot be used, and the development is simple and convenient.

Integrated development of xml and annotations: recommend the best practice xml to manage beans, and let annotations complete attribute injection     /**During use, scanning is not required, scanning is for annotations on classes*/
    

8. Proxy mode

This part needs to understand what is reflection first, understanding what is reflection can help to understand what is proxy mode, see catalog 10 for details

[The underlying mechanism of AOP (Aspect-Oriented Programming (AOP)) is dynamic proxy! ]


8.1 What AOP is used for

Without changing the original code, the enhancement of the original function is realized, which is the core idea in AOP ;


The proxy mode is divided into:
        1. Static proxy
        2. Dynamic proxy


Static proxy role analysis
/**
    * Abstract role: generally implemented by using an interface or an abstract class (equivalent to a method or behavior)
    * Real role: the role being proxied
    * Proxy role: acting as a real role; after proxying a real role, generally There will be some built-in operations.
    * Client: Use the proxy role to perform some operations
*/


Advantages and disadvantages of static agents
/**
*Advantages:
* 1. Can make our real role more pure. No longer pay attention to some public things. *
2. Public business is completed by the agent. Realized the division of labor,
* 3. When the public business expands, it becomes more centralized and convenient.
*Disadvantages:
*There are more classes (real roles), and more proxy classes (agent roles), the code to be written is doubled, the workload is increased, and the development efficiency is reduced

8.2 Static proxy

Example: [real role: landlord; abstract role (method): renting a house; agent role: intermediary; customer: person who buys a house] to describe the entire static agent

landlord:

//房东
public class Host implements Rent{

    @Override
    public void rent() {
        System.out.println("房东出租房子");
    }
}

Rent a house:

//租房
public interface Rent {
    void rent();
}

intermediary:

//中介
//这里中介去实现了租房子这个方法,就相当于中介帮助房东出租房子
public class ZhongJie implements Rent{
//去找到房东,为了获取房源
    private Host host;

    public ZhongJie() {
    }
//为房东创建实参,为了实现出租房子的方法(行为)
    public ZhongJie(Host host) {
        this.host = host;
    }

    public void rent() {
//通过房东去.出来买房子的方法
        host.rent();
//这是中介(代理对象)自带的一些方法
        seeHouse();//看房子
        hetong();//签合同
        takeMoney();//赚差价
        sell();//卖出房子
    }
/**
*对应的中介自带的方法
*/
//    看房
    public void seeHouse(){
        System.out.println("中介带你看房");
    }
//签合同
    public void hetong(){
        System.out.println("中介签合同");
    }
//赚差价
    public void takeMoney(){
        System.out.println("中介收中介费");
    }
//卖出房子
    public void sell(){
        System.out.println("卖出房子");
    }
}

Who buys a house:

public class Empty {
    public static void main(String[] args) {
//        房东要租房子
        Host host = new Host();
//        host.rent();
//        房东去找中介,中介帮房东租房子,但是代理角色一般会有一些自带的操作!
        ZhongJie zhongJie = new ZhongJie(host);
//        有了中介,租房子的人不需要面对房东,直接找中介即可
        zhongJie.rent();
    }
}

output result:

房东要出租房子
中介带你看房
中介签合同
中介收中介费
卖出房子

From the above code, it can be easily seen that the landlord only provides a method (behavior) and listing of the house I want to sell; the rest of the other things are provided by the agent (intermediary) until the house is sold sell away;

Similarly, if any other operations are required, they can be implemented directly in the intermediary.

 8.3 In-depth understanding of static proxy

Without changing the original code, the enhancement of the original function is realized

 

example

//先去写出一些方法
public interface UserService {
    void add();
    void delete();
    void update();
    void query();
}
然后去用实现类实现接口内的方法
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 query() {
        System.out.println("查询了一个用户");
    }
}

At this point, if you directly write Test test

public class Test {
    public static void main(String[] args) {
        UserServiceImpl userService = new UserServiceImpl();
        userService.add();
    }
}

It will appear that the result is

增加了一个用户

To call other methods is also to display the content of sout, but at this time, our dear Party A has made a request:

I need to add a new output on the basis of each original output, to tell the user which methods we use in the background;

 First of all, our most direct method is to write another sout in the implementation class to output the methods we use, but what if my method has 100? 1000? What if there are even more? I can’t add them one by one. , so we need to use our AOP (aspect-oriented programming) method, which is equivalent to setting up a middleman, first to get our original method, and then to add new content:

public class UserServiceDaiLi implements UserService{
//获取原有实现类方法
    private UserServiceImpl userservice;
//设置set方法
    public void setUserservice(UserServiceImpl userservice) {
        this.userservice = 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("[Debug]使用了"+msg+"方法");
    }
}

Test test:

public class Test {
    public static void main(String[] args) {
        UserServiceImpl userService = new UserServiceImpl();
        UserServiceDaiLi DaiLi = new UserServiceDaiLi();
        DaiLi.setUserservice(userService);
//因为要输出的是daili内部新写的内容
        DaiLi.add();

    }
}

The output is:

[Debug]使用了add方法
增加了一个用户

9. Dynamic proxy

/**Advantages:
* 1. It can make our real role more pure. No longer pay attention to some public things,
* 2. The public business is completed by the agent. The division of labor is realized,
* 3. The public business expands
* 4. A dynamic proxy class proxies an interface, which generally corresponds to a type of business. *
5. A dynamic proxy class can proxy multiple classes, as long as the same interface is implemented Can. 
*/

---- This part is more abstract and difficult to understand, directly upload the code, and the specific explanation is written in the code

----First of all, take the data of static proxy as an example

9.1 Examples

landlord:

//房东
public class Host implements Rent {

    @Override
    public void rent() {
        System.out.println("房东要出租房子");
    }
}

Rent a house:

//租房
public interface Rent {
    void rent();
}

Proxy object (officially ProxyInvocationHandler, named DaiLi~~~ for easy understanding):

//使用这个类自动生成代理角色
public class DaiLiInvocationHandler implements InvocationHandler {

//    被代理的接口
    private Rent rent;

    public void setRent(Rent rent) {
        this.rent = rent;
    }

//    生成得到代理类

    /**
     * @return
     * getClassLoader() 是为了加载类在哪个位置
     * getInterfaces() 表示要代理的接口是哪一个
     * this 代表InvocationHandler本身
     */
     public Object getProxy(){
       return Proxy.newProxyInstance(this.getClass().getClassLoader(),rent.getClass().getInterfaces(),this);
     }

    //(真正的处理是靠invoke方法执行)处理代理实例,并返回结果
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//        动态代理的本质就是使用反射机制实现
        seeHouse();
        Object result = method.invoke(rent,args);
        takeMoney();
        return result;
    }
    public void seeHouse(){
        System.out.println("中介带去看房子");
     }
     public void takeMoney(){
        System.out.println("中介收差价");
     }

}

The person who sells the house:

public class Client {
    public static void main(String[] args) {
//        真实角色
        Host host = new Host();
//        代理角色(暂时不存在,需要去调用set设置)
        DaiLiInvocationHandler dih = new DaiLiInvocationHandler();
//        通过调用程序处理角色,来处理我们调用的接口对象!
        dih.setRent(host);
        Rent proxy = (Rent) dih.getProxy();
        proxy.rent();
    }
}

output result:

中介带去看房子
房东要出租房子
中介收差价

9.2 Deeper understanding of dynamic proxies

Following 8.3 to learn more about dynamic proxy

Proxy object:

//使用这个类自动生成代理角色
public class DaiLiInvocationHandler implements InvocationHandler {
//代理谁:
    //被代理的接口
    private Object target;
//        setter
    public void setTarget(Object target) {
        this.target = target;
    }

    /**
     * @return
     * getClassLoader() 是为了加载类在哪个位置
     * getInterfaces() 表示要代理的接口是哪一个
     * this 代表InvocationHandler本身
     */
//生成得到代理类(固定写法,只需要更改需要实现的接口):
     public Object getProxy(){
       return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
     }
//调用代理程序的一些方法
    //(真正的处理是靠invoke方法执行)处理代理实例,并返回结果
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    //动态代理的本质就是使用反射机制实现
        /**
         * 如果这里的msg去设置单独的一个方法,
         * 那么如果我去调用删除方法,就还要在log内更改为delete
         * 但如果通过invoke的method去.出来getName,则只需要去更改前端的调用方法
         * 后端自动的去动态处理输出的内容
         */
        //        log("add");
        log(method.getName());
        Object result = method.invoke(target,args);
        return result;
    }
//    设置新增日志
    public void log(String msg){
        System.out.println("[Debug]使用了"+msg+"方法");
    }

}

User (person who rents a house):

public class Customer {
    public static void main(String[] args) {
//        真实角色
        UserServiceImpl userService = new UserServiceImpl();
//        代理角色(暂时不存在,需要去设置)
        DaiLiInvocationHandler dih = new DaiLiInvocationHandler();
        dih.setTarget(userService);//设置要代理的对象
        UserService proxy = (UserService) dih.getProxy();
        proxy.delete();
    }
}

output result:

[Debug]使用了delete方法
删除了一个用户

9.3 Summary of Proxy Mode

Here is a summary of the agency model in Zhoumu:

1. First of all, for the "reflection" problem of dynamic proxy, you must first understand what reflection is, and then look at the code of the proxy mode.

2. Secondly, the proxy mode, as the name implies, requires a proxy object to help our code achieve a clear division of labor, so that our code does not look messy, and all business operations are handed over to the proxy object; it helps us in The later maintenance work does not need to change our code, which violates the principle of opening and closing (that is, software entities should try to expand without modifying the original code ).

3. The last thing is to understand the architecture (routines). Many things are unchanged. You only need to write them down. In the later maintenance, you can change the specified content to complete the maintenance. Understand real objects, proxy objects, abstract methods and front-ends call and implementation relationship.

 10. Understanding reflection

1. What is reflection

In the running state, for any class, all properties and methods of this class can be known;

For any object, you can call any of its methods and properties

This function of dynamically obtaining information and dynamically calling methods of objects is called the reflection mechanism of the Java language.

2. Advantages of reflection:

Reflection improves program flexibility and scalability, reduces coupling, and improves self-adaptability. It allows programs to create and control objects of any class without hardcoding the target class in advance

3. Disadvantages of reflection

Performance issues, using reflection is basically an interpretation operation, which is much slower than direct code when used for field and method access. Therefore, the reflection mechanism is mainly used in system frameworks that require high flexibility and scalability, and is not recommended for ordinary programs.

11.AOP

11.1 What is AOP

AOP (Aspect Oriented Programming) means: aspect-oriented programming, a technology that realizes unified maintenance of program functions through pre-compilation and runtime dynamic proxy . AOP is a continuation of OOP, a hot spot in software development, an important content in the Spring framework, and a derivative paradigm of functional programming. AOP can be used to isolate various parts of business logic, thereby reducing the coupling degree between various parts of business logic, improving the reusability of programs, and improving the efficiency of development at the same time.

11.2 The role of Aop in Spring 

AOP terms:

1. Joinpoint

        A specific node in the program execution process, such as a method call or an exception execution, is usually a method execution.

2. Pointcut

        Refers to the connection point that needs to be processed. All method executions are connection points, and a specific connection point is the entry point (intercepted connection point)

3. Target

        Refers to the object to be notified, that is, the target object of the agent;

4. Notification (advice)

        Also known as enhancement, it is a piece of code added by an aspect to a specific connection point. In simple terms, notification refers to what to do after the intercepted connection point, so notification is the specific implementation of aspect; notification is divided into front notification, post notification, exception notification, final notification, surrounding notification;

5. Aspect

        It refers to the class that encapsulates the horizontal cutting to the system function (such as transaction processing), which is the combination of entry point and notification;

6. Weave

        It is the process of inserting the aspect code into the target object to generate a proxy object;

7. Proxy

        It means that after the notification (enhancement) is applied, a proxy object is generated;

 11.2.1 Two proxy methods of Spring AOP

One is regular JDK and one is CGLIB.

When the proxy object implements at least one interface, the JDK is used to dynamically create the proxy object by default;

CGLIB methods are used when the proxy object does not implement any interface.

If the interface is implemented, the cast must be defined with the superclass interface

Because there are not many things that can be explained clearly in words in this part, so just look at the examples

11.3 Start with the topic, first guide the package

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

Second, create a configuration file " 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">
</beans>

11.4 Specifically divided into three ways

        11.4.1 The first way: use the original SpringAPI interface

First, write the business interface and implementation class:

public interface UserSerice {
void add();
void delete();
void update();
void select();
}
public class UserServiceImpl implements UserSerice{
    @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("查询了一个用户");
    }
}

Then there are enhanced classes (pre-notification and post-notification)

public class BeforeLog implements MethodBeforeAdvice {
    /**
     *
     * @param method 要执行的目标对象的方法
     * @param args 参数
     * @param target 目标对象
     * @throws Throwable
     */
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println(method.getClass().getName()+"的"+method.getName()+"被执行了");
    }
}
public class AfterLog implements AfterReturningAdvice {
    /**
     *
     * @param returnValue 返回值
     * @param method
     * @param args
     * @param target
     * @throws Throwable
     */
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
        System.out.println("执行了"+method.getName()+"方法,返回的结果为"+returnValue);
    }
}

Then go to the spring configuration file "applicationContext.xml" to register the bean, and realize the implementation of aop cut-in.

<!--    注册bean-->
    <bean id="userService" class="com.gcx.Service.UserServiceImpl"/>
    <bean id="beforeLog" class="com.gcx.log.BeforeLog"/>
    <bean id="afterLog" class="com.gcx.log.AfterLog"/>
    <!--    配置AOP:需要导入aop的约束-->
    <aop:config>
<!--        首先需要一个切入点:expression:表达式,execution(要执行的位置 )-->
<!--        要给com.gcx.Service.UserServiceImpl这个类插入方法,但是这个类有很多方法,所以用.*(..) [两个点代表可以有任意个参数]-->
        <aop:pointcut id="pointcut" expression="execution(* com.gcx.Service.UserServiceImpl.*(..))"/>
<!--    执行环绕增加!-->
        <aop:advisor advice-ref="beforeLog" pointcut-ref="pointcut"/>
        <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
    </aop:config>

Final test.

public class Mytest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserSerice userService = (UserSerice) context.getBean("userService");
        userService.add();
    }

output result

java.lang.reflect.Method的add被执行了
增加了一个用户
执行了add方法,返回的结果为null

It can be seen from this that it has indeed added content to my original code where I want to add content, that is, enhanced code.

11.4.2 Method 2  Custom class to implement Aop

The business implementation class remains unchanged, it is still userServiceImpl

Step 1: Write one of our own cut-in classes

public class diy {
    public void logBefore(){
        System.out.println("方法执行前");
    }
    public void logAfter(){
        System.out.println("方法执行后");
    }
}

Then go to the spring configuration file "applicationContext.xml" to register the bean. 

    <bean id="diy" class="com.gcx.log.diy"/>
    <aop:config>
<!--        声明为切面(aspect)类-->
        <aop:aspect ref="diy">
<!--            切入点-->
            <aop:pointcut id="pointcut" expression="execution(* com.gcx.Service.UserServiceImpl.*(..))"/>
<!--            通知-->
            <aop:before method="logBefore" pointcut-ref="pointcut" />
            <aop:after method="logAfter" pointcut-ref="pointcut"/>
        </aop:aspect>
    </aop:config>

test

    @Test
    public void LogTest(){
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserSerice userService = context.getBean("userService", UserSerice.class);
        userService.add();
    }

output result

方法执行前
增加了一个用户
方法执行后

That's right, even if it's a cut-in class that we customize, it can also be written into our output code in a face-to-face way

11.4.3 Method 3  using annotations

Step 1: Write an enhanced class for annotation implementation

/**
 * @Aspect 标注该类是一个切面
 */
@Aspect
public class AnnotationPointCut {
    @Before("execution(* com.gcx.Service.UserServiceImpl.*(..))")
    public void before(){
        System.out.println("-----方法执行前-------");
    }
    @After("execution(* com.gcx.Service.UserServiceImpl.*(..))")
    public void after(){
        System.out.println("-----方法执行后------");
    }


    /**
     *
     * @param jp 连接点
     */
    //    在环绕增强中,我们可以给定一个参数,代表我们要获取处理切入的点
    @Around("execution(* com.gcx.Service.UserServiceImpl.*(..))")
    public void around(ProceedingJoinPoint jp) throws Throwable {
        System.out.println("======环绕前=====");
//        执行方法,此句代码的执行就表示切入点方法的执行
        Object o = jp.proceed();
        System.out.println("=====环绕后======");
        System.out.println(o);
    }
}

Step 2: In the Spring configuration file, register the bean and add configurations that support annotations

    <bean id="annotationPointCut" class="com.gcx.log.AnnotationPointCut"/>
<!--    开启注解支持  -->
    <aop:aspectj-autoproxy/>
<!--    Spring代理模式有两种:  1. JDK(默认)  2.CGlib
                               当proxy-target-class为false使用默认JDK;
                               当proxy-target-class为true使用CGlib;
                               -->
<!--    <aop:aspectj-autoproxy proxy-target-class="false"/>-->

test

@Test
    public void LogTest(){
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserSerice userService = context.getBean("userService", UserSerice.class);
        userService.add();
    }

output result

======环绕前=====
-----方法执行前-------
增加了一个用户
=====环绕后======
null
-----方法执行后------

11.5 AOP "Heart Bleeding" Summary

Pointcut declaration formula category:
    1. The pointcut is the com.gcx.Service.UserServiceImpl() method.
        <aop:pointcut id="pointcut1" expression="execution(* com.gcx.Service.UserServiceImpl())"/>
    2. The pointcut is all methods in the com.gcx.Service class that have no return value and empty parameters.
        <aop:pointcut id="pointcut2" expression= "execution(void com.gcx.Service.*())"/ >
    3. The pointcut is all methods in the com.gcx.Service class that have no return value and no requirement for parameters.
        <aop:pointcut id="pointcut3" expression="execution(void com.gcx.Service.*(.. ))"/>
    4. The pointcut is all methods in the com.gcx.Service class that have no requirement for the return value and the parameter is empty.
        <aop:pointcut id="pointcut4" expression="execution(* com.gcx.Service. *())"/>
    5. The pointcut is all methods in the com.gcx.Service class, and there is no requirement for the return value and parameters.
        <aop:pointcut id="pointcut5" expression="execution(* com.gcx.Service.*(..))"/>
    6. The pointcut is all methods of all classes in the com.gcx. package, and there is no requirement for return values ​​and parameters.
        <aop:pointcut id="pointcut6" expression="execution(* com.gcx.*.*(. .))"/>
    7. The pointcut is the UserServiceImpl method of all classes in the com.gcx package. There is no requirement for the return value and parameters.
        <aop:pointcut id="pointcutbag6" expression="execution(* com.gcx .*.UserServiceImpl(..))"/>
    8. For all methods of all classes, there are no requirements for return values ​​and parameters.        
        <aop:pointcut id="pointcutbag7" expression="execution(* *(..))"/>

Notification strategy and execution order:
    1. Pre-notification (before): Notification executed before the execution of the target method
    2. Post-notification (after): Notification executed after the execution of the target method.
    3. After-throwing: The notification that is executed when the target method throws an exception.
    4. After-returning: Notification that the target method is successfully executed.
    5. Surrounding notification (around): the notification that additional code can be executed before and after the execution of the target method
    <!--The execution order of the notification is related to the order of configuration in the xml file -->
        //The method of surrounding the notification must follow the following Definition rules of    
        //1: must have a parameter of ProceedingJoinPoint type,     //2         :
        must have a return value of Object type    
        //3: execute Object v = point.proceed(); between enhanced business logic before and after    
/4: The method returns return v at the end;
    Example: public Object method5(ProceedingJoinPoint point) throws Throwable {                System.out.println("~~~~~~~~~~~~~ surround notification before~~~~~~ ~~~~~");

    //point.proceed (args) indicates the execution request method. Before this method, it indicates the pre-point cut, and after this method, it indicates the post-cut point. The execution of this sentence means the execution of the point-cut method. Object v = point.proceed
    ( );
    System.out.println("~~~~~~~~~~~~~ surround notification after~~~~~~~~~~~~~");
    return v;
    } 

 Summary of notification rules:
    Using xml configuration, the execution order of notifications is related to the order of configuration.
    1. Use pre-notification, post-notification, final notification
        1.1 No abnormal pre-notification > entry point method -> post-notification and final notification (the order of execution is determined by the order of xml configuration)
        1.2 Pre-notification > entry point with exception Method -> post notification > exception notification
    2. surround notification, exception notification
        2.1 no exception: surround notification pre > entry point method > surround notification post
        2.2 with exception: surround notification pre > entry point method > exception notification
    3. Use all notifications:
        3.1 No exception: The execution sequence is as follows:
            3.1.1 Pre-advice and pre-surround notification (according to the xml configuration order)
            3.1.2 Entry point method
            3.1.3 Post-notification, final notification, surround notification post-position (There are two cases of execution according to the order of xml configuration. One is that either front or surround exists, and the other is that both front and surround exist without other configurations in the middle.) 3.2 There are exceptions: the execution sequence is as follows: 3.2.1 Pre
        -
            notification
            3.2.2 Entry point method 3.2.3
            Post notification, exception notification (execution sequence is the same as above)
    Summary: When there are no other configuration items between the front and surround, post, exception , the final execution order is the same as the configuration

12. Declarative transactions 

1. Transactions are very important in the project development process, involving data "consistency" issues!
2. Transaction management is an essential technology in enterprise-level application development to ensure data integrity and consistency.
3. A transaction is to treat a series of actions as an independent unit of work. These actions are either all completed or all of them do not work.

 12.1 Four attributes of transactions

1. Atomicity: A transaction is an atomic operation consisting of a series of actions. The atomicity of a transaction ensures that the actions are either completed or not at all. 2. Consistency: Once
all transactional actions are completed, the transaction will be committed. Data and resources are in a consistent state that satisfies business rules
3. Isolation: Multiple transactions may process the same data at the same time, so each transaction should be isolated from other transactions to prevent data corruption
4. Persistence : Once the transaction is completed, no matter what error occurs in the system, the result will not be affected. Typically, transaction results are written to persistent storage

12.2 Transaction Management in Spring 

Spring supports programmatic transaction management and declarative transaction management.
1. Declarative transaction AOP:
generally easier to use than programmatic transactions.
Separate transaction management code from business methods, and implement transaction management in a declarative manner.
Take transaction management as a cross-cutting concern, and modularize it through the AOP method. Spring supports declarative transaction management through the Spring AOP framework.
2. Programmatic transactions: need to manage transactions in code:
embed transaction management code into business methods to control transaction commit and rollback
Disadvantages: additional transaction management code must be included in each transaction operation business logic

12.2.1 Transaction Manager 

No matter which transaction management strategy (programmatic or declarative) Spring uses, a transaction manager is required.
It is Spring's core transaction management abstraction that encapsulates a set of technology-independent methods.

12.3 Spring transaction propagation features 

Transaction propagation behavior is how transactions propagate among multiple transaction methods when they call each other. Spring supports 7 kinds of transaction propagation behaviors:
1.propagation_requierd: If there is no transaction currently, create a new transaction, if there is already a transaction, join this transaction, this is the most common choice.
2.propagation_supports: support the current transaction, if there is no current transaction, it will be executed in a non-transactional method.
3.propagation_mandatory: use the current transaction, if there is no current transaction, an exception will be thrown.
4.propagation_required_new: Create a new transaction, if there is a current transaction, suspend the current transaction.
5.propagation_not_supported: Perform operations in a non-transactional manner. If there is a current transaction, suspend the current transaction.
6.propagation_never: Perform operations in a non-transactional manner, and throw an exception if the current transaction exists.
7.propagation_nested: If a transaction currently exists, execute it within a nested transaction. If there is no current transaction, perform operations similar to propagation_required.
Spring's default transaction propagation behavior is PROPAGATION_REQUIRED, which is suitable for most cases.

12.4 Constrained import of header files 

xmlns:tx="http://www.springframework.org/schema/aop"
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
xmlns:tx="http://www.springframework.org/schema/tx"
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">

12.5 Case 

Entity class (because you want to write constructor injection, you need to set empty parameters and parameterized construction methods)

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private int id;
    private String name;
    private int pwd;
}

UserMapper

public interface UserMapper {
//    查询全部用户信息
    List<User> selectUser();
//    添加一个用户
    int addUser(User user);
//    根据id删除一个用户
    int deleteUser(int id);
}

UserMapper.xml (write sql statement)

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.gcx.mapper.UserMapper">
    <select id="selectUser" resultType="user">
        select *from user;
    </select>
    <insert id="addUser" parameterType="user">
        insert into user (id,name,pwd) values(#{id},#{name},#{pwd})
    </insert>
    <delete id="deleteUser" parameterType="int">
        delete from user where id = #{id}
    </delete>

</mapper>

mybatis-config.xml (mapper configuration file)

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<!--核心配置文件-->
<configuration>
<!--别名管理-->
    <typeAliases>
        <package name="com.gcx.pojo"/>
    </typeAliases>
//使用Spring绑定配置文件,省略配置mapper命名空间
</configuration>

spring-dao.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"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/tx
        https://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--DataSource:使用Spring的数据源替换Mybatis的配置  c3p0 dbcp druid
这里使用Spring提供的jdbc:org.springframework.jdbc.datasource-->
    <bean id="datasource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=false&amp;useUnicode=true&amp;characterEncoding=UTF-8&amp;serverTimezone=Asia/Shanghai"/>
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
    </bean>


    <!--    配置sqlSessionFactory-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="datasource"/>
<!--    绑定Mybatis配置文件-->
    <property name="configLocation" value="classpath:mybatis-config.xml"/>
    <property name="mapperLocations" value="classpath:com/gcx/mapper/*.xml"/>
</bean>
<!--   SqlSessionTemplate:就是我们使用的SqlSession -->
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<!--    只能使用构造器注入SqlSessionFactory,因为没有set方法-->
    <constructor-arg index="0" ref="sqlSessionFactory"/>
</bean>
    <!--    配置声明式事务-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="datasource"/>
    </bean>
    <!--    结合AOP,实现事务的置入-->
    <!--    配置事务通知:-->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <!--        给那些方法配置事务:-->
        <tx:attributes>
            <!--            配置事务的传播特性:propagation 默认为 REQUIRED-->
            <tx:method name="add" propagation="REQUIRED"/>
            <tx:method name="delete" propagation="REQUIRED"/>
            <tx:method name="update" propagation="REQUIRED"/>
            <!--            read-only:只读-->
            <tx:method name="query" read-only="true"/>
            <!--            配置所有方法-->
            <tx:method name="*" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>
    <!--    配置事务切入-->
    <aop:config>
        <aop:pointcut id="pointcut" expression="execution(* com.gcx.mapper.*.*(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut"/>
    </aop:config>
</beans>

  applicationContext.xml (Spring configuration file)

<?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="spring-dao.xml"/>
    <bean id="userMapper" class="com.gcx.mapper.UserMapperImpl">
        <property name="sqlSession" ref="sqlSession"/>
    </bean>
</beans>

UserMapperImpl (implementation class)

/**
 * 另一种写法,直接继承SqlSessionDaoSupport;
 * public class UserMapperImpl extends SqlSessionDaoSupport implements UserMapper{}
 * 该方法内部已经写好了构造SqlSessionTemplate类型的变量sqlSession,并创建了SqlSessionFactory工厂
 */
public class UserMapperImpl implements UserMapper{
    private SqlSessionTemplate sqlSession;

    public void setSqlSession(SqlSessionTemplate sqlSession) {
        this.sqlSession = sqlSession;
    }
    public List<User> selectUser() {
        User user = new User(7, "小孟", 123134);
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        mapper.addUser(user);
        mapper.deleteUser(6);
        return mapper.selectUser();
    }


    public int addUser(User user) {
        return sqlSession.getMapper(UserMapper.class).addUser(user);
    }

    public int deleteUser(int id) {
        return sqlSession.getMapper(UserMapper.class).deleteUser(id);
    }
}

test test

public class Mytest {
    @Test
    public void test(){
        ApplicationContext Context = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserMapper userMapper = Context.getBean("userMapper", UserMapper.class);
        List<User> users = userMapper.selectUser();

        for (User user : users) {
            System.out.println(user);

        }
    }
}

 output result

User(id=1, name=小顾, pwd=123456)
User(id=2, name=小董, pwd=123666)
User(id=3, name=小杨, pwd=1234567)
User(id=4, name=小孟, pwd=1234567)
User(id=5, name=小鑫, pwd=122223)
User(id=7, name=小孟, pwd=123134)

13. Periodic self-summarization

After nearly two weeks of self-study, I understand what Spring is. The two major interview points "IOC control inversion" and "AOP aspect programming" are more difficult to learn; understand the Spring configuration file. How to write, what is included in it, what is it used for, N multiple ways of bean injection, how to use Spring to automatically connect to the database, it does not need to be as cumbersome as JDBC, two different proxy modes, various AOP Methods for implementing code enhancements, various notifications, and declarative transactions.

The most fortunate thing is that in the process of writing these codes, I encountered many problems and reported many errors, but I did not give up. Various Baidu and csdn searched for solutions to the problems, so continue to work hard and persevere, and there will be progress!

Guess you like

Origin blog.csdn.net/m0_74135466/article/details/128227021