An article to learn Spring5! !

This article is the notes made after studying Spring5 of Shang Silicon Valley at station b , I hope it will be helpful to everyone!

1. Overview of the Spring Framework

  1. Spring is a lightweight open source JavaEE framework.

  2. Spring can solve the complexities of enterprise application development.

  3. Spring has two core parts: IOC and Aop.

    (1) IOC: Inversion of control, handing over the object creation process to Spring for management

    (2) Aop: Aspect-oriented, without modifying the source code for function enhancement

  4. Spring features:

    (1) Convenient decoupling and simplified development

    (2) Aop programming support

    (3) Convenient program testing

    (4) Easy to integrate with other frameworks

    (5) Convenient for business operations

    (6) Reduce the difficulty of API development

2. IOC container

1. IOC concept and principle

(1) Concept:

  • Inversion of control, the process of object creation and object invocation is handed over to spring for management.

  • Purpose: Reduce coupling.

  • The underlying principle: xml, reflection, factory pattern

  • Spring provides two implementations of the IOC container (two interfaces)

    • BeanFactory : The interface used internally by Spring, developers are not encouraged to use it. Features: The object will not be created when the configuration file is loaded, and the object will be created when the object is obtained.

    • **ApplicationContext: **The sub-interface of BeanFactory provides more powerful functions and is generally used by developers. Features: When loading the configuration file, the objects in the configuration file will be created.

    • ApplicationContext two commonly used implementation classes:

      • FileSystemXmlApplicationContext: absolute path, counting from the drive letter
      • ClassPathXmlApplicationContext: relative path, starting from src
      image-20210720000922536

What is Bean Management? Bean management refers to two operations: Spring creates objects and Spring injects properties

Bean management has two modes of operation: based on xml configuration files and based on annotations

2. IOC operation Bean management (based on xml)

xml implements Bean management:

(1) Create objects based on xml:

image-20210719101725911
  • Use bean tags in Spring configuration files to create objects
  • The bean tag has many attributes, commonly used attributes:
    • id: unique identifier
    • class: class path
  • When creating an object, the no-argument constructor is executed by default

(2) Inject attributes based on xml:

The first method: use the set method for injection:

First, provide a set method for the properties of the class:

public class User {
    
    

    private String userName;
    private String userAge;

    public void setUserName(String userName) {
    
    
        this.userName = userName;
    }

    public void setUserAge(String userAge) {
    
    
        this.userAge = userAge;
    }

    public String getUserName() {
    
    
        return userName;
    }

    public String getUserAge() {
    
    
        return userAge;
    }
}

Then perform attribute injection through the property tag in the xml configuration file

    <!--配置User对象-->
    <bean id="user" class="com.oymn.spring5.User">
        <property name="userName" value="haha"></property>
        <property name="userAge" value="18"></property>
    </bean>

This is done

    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean1.xml");
    User user = applicationContext.getBean("user", User.class);
    System.out.println(user.getUserName() + "     " + user.getUserAge());

The second method: use a parameterized constructor for injection

First provide a parameterized constructor

public class User {
    
    

    private String userName;
    private String userAge;

    public User(String userName, String userAge){
    
    
        this.userName = userName;
        this.userAge = userAge;
    }
}

Then perform attribute injection through the constructor-arg tag in the xml configuration file

    <!--配置User对象-->
    <bean id="user" class="com.oymn.spring5.User">
        <constructor-arg name="userName" value="haha"></constructor-arg>
        <constructor-arg name="userAge" value="18"></constructor-arg>
    </bean>

The third method: p namespace injection (just understand)

First add the p namespace in the xml configuration file, and operate in the bean tag

image-20210719104230761

Then provide the set method

public class User {
    
    

    private String userName;
    private String userAge;

    public User() {
    
    
    }

    public void setUserName(String userName) {
    
    
        this.userName = userName;
    }

    public void setUserAge(String userAge) {
    
    
        this.userAge = userAge;
    }
}

(3) xml injects other attributes

  1. null value
    <!--配置User对象-->
    <bean id="user" class="com.oymn.spring5.User">
        <property name="userName"> <null/> </property>
    </bean>
  1. Attribute value contains special symbols

    Suppose now the userName attribute needs to be assigned the value < haha ​​>

    If it is declared directly in the value as above, an error will be reported because it contains the special symbol <>

    image-20210720003501206

    needs to be <![CDATA[值]]>represented by

    image-20210720003720138
  2. Injection property - external bean

    There are two classes: UserService and UserDaoImpl, where UserDaoImpl implements the UserDao interface

    public class UserService {
          
          
    
        private UserDao userDao;
    
        public void setUserDao(UserDao userDao){
          
          
            this.userDao = userDao;
        }
    
        public void add(){
          
          
            System.out.println("add");
        }
    }
    

    Create userDaoImpl by ref

    <bean id="userDaoImpl" class="com.oymn.spring5.UserDaoImpl"></bean>
    
    <bean id="userService" class="com.oymn.spring5.UserService">
        <property name="userDao" ref="userDaoImpl"></property>
    </bean>
    
  3. Injection property - inner bean

    Not through the ref attribute, but through nesting a bean tag

<!--内部 bean-->
<bean id="emp" class="com.atguigu.spring5.bean.Emp">
     <!--设置两个普通属性-->
     <property name="ename" value="lucy"></property>
     <property name="gender" value=""></property>
     <!--设置对象类型属性-->
     <property name="dept">
         <bean id="dept" class="com.atguigu.spring5.bean.Dept">
        	 <property name="dname" value="安保部"></property>
         </bean>
     </property>
</bean>
  1. Injecting properties - cascading assignments

    Writing method 1: that is, the external bean mentioned above, the external bean is obtained through the ref attribute

    Writing method two:

    There are two attributes of ename and dept in the emp class, among which dept has the dname attribute, and the second writing method requires emp to provide the get method of the dept attribute.

    <!--级联赋值-->
    <bean id="emp" class="com.atguigu.spring5.bean.Emp">
        <!--设置两个普通属性-->
        <property name="ename" value="lucy"></property> <property name="gender" value=""></property>
        <!--写法一-->
    	<property name="dept" ref="dept"></property>
        <!--写法二-->
        <property name="dept.dname" value="技术部"></property>
    </bean>
    <bean id="dept" class="com.atguigu.spring5.bean.Dept">
        <property name="dname" value="财务部"></property>
    </bean>
    
  2. Inject collection properties (Array, List, Map)

Suppose there is a Stu class

public class Stu {
    
    

    private String[] courses;
    private List<String> list;
    private Map<String,String> map;
    private Set<String> set;

    public void setCourses(String[] courses) {
    
    
        this.courses = courses;
    }

    public void setList(List<String> list) {
    
    
        this.list = list;
    }

    public void setMap(Map<String, String> map) {
    
    
        this.map = map;
    }

    public void setSet(Set<String> set) {
    
    
        this.set = set;
    }
}

Inject these collection attributes in the xml configuration file

<bean id="stu" class="com.oymn.spring5.Stu">
    <!--数组类型属性注入-->
    <property name="courses">
        <array>
            <value>java课程</value>
            <value>数据库课程</value>
        </array>
    </property>
    <!--List类型属性注入-->
    <property name="list">
        <list>
            <value>张三</value>
            <value>李四</value>
        </list>
    </property>
    <!--Map类型属性注入-->
    <property name="map">
        <map>
            <entry key="JAVA" value="java"></entry>
            <entry key="PHP" value="php"></entry>
        </map>
    </property>
    <!--Set类型属性注入-->
    <property name="set">
        <set>
            <value>Mysql</value>
            <value>Redis</value>
        </set>
    </property>
</bean>
  1. The above collection values ​​are all strings, if they are objects, they are as follows:

    Writing method: collection + external bean

<!--创建多个 course 对象-->
<bean id="course1" class="com.atguigu.spring5.collectiontype.Course">
	<property name="cname" value="Spring5 框架"></property>
</bean>
<bean id="course2" class="com.atguigu.spring5.collectiontype.Course">
	<property name="cname" value="MyBatis 框架"></property>
</bean>

<!--注入 list 集合类型,值是对象-->
<property name="courseList">
    <list>
        <ref bean="course1"></ref>
        <ref bean="course2"></ref>
    </list>
</property>
  1. Extract the collection injection part

    Use the util tag so that different beans can use the same collection injection part.

    <!--将集合注入部分提取出来-->
    <util:list id="booklist">
        <value>易筋经</value>
        <value>九阳神功</value>
    </util:list>
    
    <bean id="book" class="com.oymn.spring5.Book">
        <property name="list" ref="booklist"></property>
    </bean>
    
  2. FactoryBean

    Spring has two kinds of beans, one is ordinary beans and the other is factory beans (FactoryBean)

    I don't quite understand this piece, and I don't know what it's useful for, so let's leave it for now.

Bean scope:

  • In Spring, beans are singleton objects by default

image-20210719113035226

The execution results are the same:

image-20210719113122345
  • Use the scope attribute of the bean tag to set single or multiple instances.

Scope attribute value:

  • **singleton: **The default value, which means a single instance object. The singleton object is created when the configuration file is loaded.
  • prototype: Indicates a multi-instance object. Instead of creating an object when the configuration file is loaded, a multi-instance object is created when the getBean method is called.
image-20210719113500730

The execution result is different:

image-20210719113518353

Bean life cycle:

  1. Bean life cycle:

(1) Create a bean instance through a constructor (no parameter construction)

(2) Set values ​​for bean properties and reference other beans (call the set method)

(3) Pass the bean instance to the postProcessBeforeInitialization method of the bean post-processor

(4) Call the bean initialization method (the method that needs to be configured and initialized)

(5) Pass the bean instance to the postProcessAfterInitialization method of the bean post-processor

(6) The bean is ready to use (the object is obtained)

(7) When the container is closed, call the bean's destruction method (the method that needs to be configured and destroyed)

  1. Demo bean life cycle
public class Orders {
    
    
    private String orderName;

    public Orders() {
    
    
        System.out.println("第一步:执行无参构造方法创建bean实例");
    }

    public void setOrderName(String orderName) {
    
    
        this.orderName = orderName;
        System.out.println("第二步:调用set方法设置属性值");
    }

    //初始化方法
    public void initMethod(){
    
    
        System.out.println("第四步:执行初始化方法");
    }

    //销毁方法
    public void destroyMethod(){
    
    
        System.out.println("第七步:执行销毁方法");
    }
}
//实现后置处理器,需要实现BeanPostProcessor接口
public class MyBeanPost implements BeanPostProcessor {
    
    

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    
    
        System.out.println("第三步:将bean实例传递给bean后置处理器的postProcessBeforeInitialization方法");
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    
    
        System.out.println("第五步:将bean实例传递给bean后置处理器的postProcessAfterInitialization方法");
        return bean;
    }
}

<bean id="orders" class="com.oymn.spring5.Orders" init-method="initMethod" destroy-method="destroyMethod">
    <property name="orderName" value="hahah"></property>
</bean>

<!--配置bean后置处理器,这样配置后整个xml里面的bean用的都是这个后置处理器-->
<bean id="myBeanPost" class="com.oymn.spring5.MyBeanPost"></bean>
@Test
public void testOrders(){
    
    

    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");

    Orders orders = context.getBean("orders", Orders.class);

    System.out.println("第六步:获取bean实例对象");
    System.out.println(orders);

    //手动让bean实例销毁
    context.close();
}

Results of the:

image-20210720122628081

xml autowiring:

  • According to the specified assembly rules (property name or property type), Spring automatically injects the matching property value

  • Automatically assemble according to the attribute name: the name dept of the attribute in emp is required to be the same as the id value dept of the bean tag in order to be recognized

  • <!--指定autowire属性值为byName-->
    <bean id="emp" class="com.oymn.spring5.Emp" autowire="byName"></bean>
    
    <bean id="dept" class="com.oymn.spring5.Dept"></bean>
    
  • Automatic assembly according to attribute type: It is required that there cannot be two beans of the same type in the same xml file, otherwise it cannot be identified which one

  • <!--指定autowire属性值为byType-->
    <bean id="emp" class="com.oymn.spring5.Emp" autowire="byType"></bean>
    
    <bean id="dept" class="com.oymn.spring5.Dept"></bean>
    

Manipulate beans through external properties files:

For example, configure database information:

  1. Import the druid connection pool jar package

  2. Create external property files, properties format files, write database information

    image-20210731004522456
  3. Introduce the context namespace, and import the external property file through the context tag, and use "${}" to obtain the corresponding value in the file

    image-20210731010320233

3. IOC operation Bean management (based on annotations)

  • Format: @ annotation name (attribute name = attribute value, attribute name = attribute value, ...)

  • Annotations can be applied to classes, properties, and methods.

  • The purpose of using annotations: Simplify xml configuration

(1) Create objects based on annotations:

Spring provides four annotations for creating objects:

  • @Component
  • @Service: generally used in the Service layer
  • @Controller: generally used in the web layer
  • @ Repository: Generally used for Dao layer

process:

  1. Import dependencies:

    image-20210731144620261
  2. Enable component scanning: scan all annotated classes under the base-package package and create objects for them

    <context:component-scan base-package="com.oymn"></context:component-scan>
    
  3. com.oymn.spring5.Service has a stuService class

    //这里通过@Component注解来创建对象,括号中value的值等同于之前xml创建对象使用的id,为了后面使用时通过id来获取对象
    //括号中的内容也可以省略,默认是类名并且首字母小写
    //可以用其他三个注解
    @Component(value="stuService")
    public class StuService {
          
          
        public void add(){
          
          
            System.out.println("addService");
        }
    }
    
  4. In this way, the stuService object can be obtained through the getBean method

    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean4.xml");
    StuService stuService = context.getBean("stuService", StuService.class);
    System.out.println(stuService);
    stuService.add();
    

Turn on the detailed configuration of component scanning:

  1. Use-default-filters is set to false to indicate that the default filter is not used, and the include-filter is set to scan only all @Controller-modified classes under the com.oymn package.
<context:component-scan base-package="com.oymn" use-default-filters="false">
    <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
  1. exclude-filter sets which annotations are not to be scanned, in the example the class modified by @Controller is not to be scanned
<context:component-scan base-package="com.oymn">
    <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>

(2) Attribute injection based on annotations:

  • @Autowired : Autowire based on property type

    Create the StuDao interface and StuDaoImpl implementation class, and add object creation annotations for StuDaoImpl

    public interface StuDao {
          
          
        public void add();
    }
    
    @Repository
    public class StuDaoImpl implements StuDao {
          
          
        @Override
        public void add() {
          
          
            System.out.println("StuDaoImpl");
        }
    }
    

    Add the StuDao attribute to the StuService class, add the @Autowire annotation to it, and spring will automatically create a StuDaoImpl object for the stuDao attribute

    @Component(value="stuService")
    public class StuService {
          
          
        
        @Autowired
        public StuDao stuDao;
    
        public void add(){
          
          
            System.out.println("addService");
            stuDao.add();
        }
    }
    
    @Test
    public void test1(){
          
          
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean4.xml");
        StuService stuService = context.getBean("stuService", StuService.class);
        System.out.println(stuService);
        stuService.add();
    }
    

    Test Results:

    image-20210731164052536
  • @Qualifier : Autowire based on attribute names

    When encountering an interface with many implementation classes, automatic assembly cannot be completed only through @Autowire, so you need to use @Qualifier to lock a class by name

    @Component(value="stuService")
    public class StuService {
          
          
    
        @Autowired
        @Qualifier(value="stuDaoImpl")  //这样就能显式指定stuDaoImpl这个实现类
        public StuDao stuDao;
    
        public void add(){
          
          
            System.out.println("addService");
            stuDao.add();
        }
    }
    
  • @Resource : can be injected by type or by name

    @Component(value="stuService")
    public class StuService {
          
          
        
        //@Resource   //根据类型进行注入
        @Resource(name="stuDaoImpl")  //根据名称进行注入
        public StuDao stuDao;
    
        public void add(){
          
          
            System.out.println("addService");
            stuDao.add();
        }
    }
    
  • @Value : Inject normal type properties

    @Value(value = "abc")
    private String name;
    

(3) Fully annotated development:

Create a configuration class to replace the xml configuration file

@Configuration    //表明为一个配置类
@ComponentScan(basePackages = "com.oymn")   //开启组件扫描
public class SpringConfig {
    
    
}

Test class:

@Test
public void test2(){
    
    
    //创建AnnotationConfigApplicationContext对象
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
    StuService stuService = context.getBean("stuService", StuService.class);
    System.out.println(stuService);
    stuService.add();
}

3. AOP

1. The underlying principle

  • Aspect-oriented programming , using AOP can isolate each part of the business logic, so that the coupling degree between the parts of the business logic is reduced , the reusability of the program is improved, and the efficiency of development is improved. In layman's terms, it is to add new functions without modifying the code.

  • The underlying layer is implemented through dynamic proxy:

    • The first type: In the case of an interface , use JDK dynamic proxy: create a proxy object of the interface implementation class .
    • The second type: In the case of no interface , use CGLIB dynamic proxy: create a proxy object of the current class subclass .

Example of JDK dynamic proxy:

  • Create a proxy class through the newProxyInstance method of the java.lang.reflect.Proxy class .

  • newProxyInstance method:

  • image-20210801004308007

    Parameter one: class loader

    Parameter 2: The class where the enhanced method is located, the interface implemented by this class, supports multiple interfaces

    Parameter 3: implement the InvocationHandle interface, rewrite the invoke method to add new functions

Code example:

public interface UserDao {
    
    
    public int add(int a, int b);
    public int multi(int a, int b);
}
public class UserDaoImpl implements UserDao {
    
    
    @Override
    public int add(int a, int b) {
    
    
        return a+b;
    }

    @Override
    public int multi(int a, int b) {
    
    
        return a*b;
    }
}
public class Main {
    
    

    @Test
    public void test1(){
    
    

        //所需代理的类实现的接口,支持多个接口
        Class[] interfaces = {
    
    UserDao.class};
		
        UserDao userDao = new UserDaoImpl();
        
		//调用newProxyInstance方法来创建代理类
        UserDao userDaoProxy = (UserDao) Proxy.newProxyInstance(Main.class.getClassLoader(), interfaces, new UserDaoProxy(userDao));
		
        int result = userDaoProxy.add(1, 2);
        System.out.println(result);
    }

    //创建内部类,实现InvocationHandler接口,重写invoke方法,添加新功能
    class UserDaoProxy implements InvocationHandler {
    
    

        Object obj;
		//通过有参构造函数将所需代理的类传过来
        public UserDaoProxy(Object obj){
    
    
            this.obj = obj;
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
    

            System.out.println("进入" + method.getName() + "方法,这是新增的代码,参数有" + Arrays.toString(args));
            
			//执行原有的代码
            Object invoke = method.invoke(obj, args);
            
            System.out.println("方法原先的内容执行完了");
            
            return invoke;
        }
    }
}

operation result:

image-20210801005210363

2. Realize AOP operation based on AspectJ

(1) AOP related terms:

  • Connection point : A method in a class that can be enhanced is called a connection point.
  • Entry point : The method that is actually enhanced is called an entry point.
  • Notice : Enhanced that part of the logic code. There are several types of notifications:
    • Pre-notification: The enhanced part of the code is in front of the original code.
    • Post-notification: The enhanced part of the code is behind the original code.
    • Surrounding notifications: The enhanced code is both before and after the original code.
    • Exception notification: The original code will be executed after an exception occurs.
    • Final notice: similar to the part of finally
  • Aspect : Refers to the action of applying advice to a pointcut.

(2) There are two ways to implement AOP based on AspectJ:

  • Based on xml configuration file
  • Annotation-based approach

(3) Entry point expression

  • Syntax: execution([permission modifier] [return type] [full class path] [method name] [parameter list])

  • Example 1: Enhance the add in the com.atguigu.dao.BookDao class

    execution(* com.auguigu.dao.BookDao.add(..))
    
  • Example 2: Enhance all the methods in the com.atguigu.dao.BookDao class

    execution(* com.atguigu.dao.BookDao.*(..))
    
  • Example 3: Enhance all classes and methods in the com.atguigu.dao package

    execution(* com.atguigu.dao.*.* (..))
    

(1) Based on the annotation method

@Component
public class User {
    
    
    public void add(){
    
        
        System.out.println("User.add()");
    }
}
@Component
@Aspect   //使用Aspect注解
public class UserProxy {
    
    
    //前置通知
    @Before(value="execution(* com.oymn.spring5.User.add(..))")
    public void before(){
    
    
        System.out.println("UserProxy.before()");
    }
    
    //后置通知
    @AfterReturning(value="execution(* com.oymn.spring5.User.add(..))")
    public void afterReturning(){
    
    
        System.out.println("UserProxy.afterReturning()");
    }
    
    //最终通知
    @After(value="execution(* com.oymn.spring5.User.add(..))")
    public void After(){
    
    
        System.out.println("UserProxy.After()");
    }

    //异常通知
    @AfterThrowing(value="execution(* com.oymn.spring5.User.add(..))")
    public void AfterThrowing(){
    
    
        System.out.println("UserProxy.AfterThrowing()");
    }

    //环绕通知
    @Around(value="execution(* com.oymn.spring5.User.add(..))")
    public void Around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
    
    

        System.out.println("UserProxy.Around()   _1");

        //调用proceed方法执行原先部分的代码
        proceedingJoinPoint.proceed();

        System.out.println("UserProxy.Around()   _2");
    }
}

Configuration xml file:

<!--开启组件扫描-->
<context:component-scan base-package="com.oymn"></context:component-scan>
<!--开启AspectJ生成代理对象-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>

Test class:

@Test
public void test2(){
    
    
    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
    User user = context.getBean("user", User.class);
    user.add();
}

operation result:

image-20210801210024676

There is no exception notification in the running result, add it in the add methodint i = 1/0;

public void add(){
    
    
    int i = 1/0;
    System.out.println("User.add()");
}

Running results: It can also be seen from here, but when an exception occurs, the After final notification is executed, but the AfterReturning post notification is not executed.

image-20210801210304774

For the above example, there are many notification entry points with the same method, so the be extracted: via @Pointcut annotation

@Pointcut(value="execution(* com.oymn.spring5.User.add(..))")
public void pointDemo(){
    
    
    
}

//前置通知
@Before(value="pointDemo()")
public void before(){
    
    
    System.out.println("UserProxy.before()");
}

Set the enhanced class priority:

When multiple enhancement classes enhance the same method, you can set the priority of the enhancement class through **@Order (number value), the smaller the number, the higher the priority. **

@Component
@Aspect
@Order(1)
public class PersonProxy

Fully annotated development :

You can completely get rid of the xml configuration file by configuring the class:

@Configuration
@ComponentScan(basePackages = "com.oymn.spring5")
//@EnableAspectJAutoProxy注解相当于上面xml文件中配置的 <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
@EnableAspectJAutoProxy(proxyTargetClass = true)  
public class Config {
    
    
}

(2) XML-based method

This method is not very used in development, just understand it.

Create Book and BookProxy classes

public class Book {
    
    
    public void buy(){
    
    
        System.out.println("buy()");
    }
}
public class BookProxy {
    
    
    public void before(){
    
    
        System.out.println("before()");
    }
}

Configuration xml file:

<!--创建对象-->
<bean id="book" class="com.oymn.spring5.Book"></bean>
<bean id="bookProxy" class="com.oymn.spring5.BookProxy"></bean>

<aop:config>
    <!--切入点-->
    <aop:pointcut id="p" expression="execution(* com.oymn.spring5.Book.buy(..))"/>
    <!--配置切面-->
    <aop:aspect ref="bookProxy">
        <aop:before method="before" pointcut-ref="p"/>  <!--将bookProxy中的before方法配置为切入点的前置通知-->
    </aop:aspect>
</aop:config>

Four, JdbcTemplate

  • Spring encapsulates JDBC and uses JdbcTemplate to facilitate the operation of the database.

(1) Addition, deletion and modification operations:

int update(String sql, Object... args);

(2) Query: return a value

T queryForObject(String sql,Class<T> requiredType);

(3) Query: return an object

T queryForObject(String sql,RowMapper<T> rowMapper,Object ... args);

(4) Query: return collection

List<T> query(String sql,RowMapper<T> rowMapper,Object... args);

(5) Batch addition, deletion and modification:

int[] batchUpdate(String sql,List<Object[]> batchArgs);

Example:

  1. Import related jar packages

    image-20210801231107102
  2. Configure the database connection pool; configure the JdbcTemplate object

    <context:component-scan base-package="com.oymn"></context:component-scan>
    
    <!--配置数据库连接池 -->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
        <property name="url" value="jdbc:mysql://localhost:3306/book" />
        <property name="username" value="root" />
        <property name="password" value="000000" />
        <property name="driverClassName" value="com.mysql.jdbc.Driver" />
    </bean>
    
    <!--创建JdbcTemplate对象-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <!--注入数据库连接池-->
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    
  3. Create Service class and Dao class, inject JdbcTemplate object in Dao class

    public interface BookDao {
          
          
    
        public void add(Book book);  //添加图书
    
        public void update(Book book);  //修改图书
    
        public void delete(int id);  //删除图书
    
        public int queryCount();   //查询数量
    
        public Book queryBookById(int id);  //查询某本书
    
        public List<Book> queryBooks();   //查询所有书
    
        public void batchAddBook(List<Object[]> books);  //批量添加图书
    
        public void batchUpdateBook(List<Object[]> books);  //批量修改图书
    
        public void batchDeleteBook(List<Object[]> args);  //批量删除图书
    }
    
    
    @Repository
    public class BookDaoImpl implements BookDao {
          
          
    
        @Autowired
        private JdbcTemplate jdbcTemplate;
    
        @Override
        public void add(Book book) {
          
          
            String sql = "insert into t_book set name=?,price=?";
            Object[] args = {
          
          book.getBookName(),book.getBookPrice()};
            int update = jdbcTemplate.update(sql, args);
            System.out.println(update);
        }
    
        @Override
        public void update(Book book) {
          
          
            String sql = "update t_book set name=?,price=? where id=?";
            Object[] args = {
          
          book.getBookName(),book.getBookPrice(),book.getBookId()};
            int update = jdbcTemplate.update(sql, args);
            System.out.println(update);
        }
    
        @Override
        public void delete(int id) {
          
          
            String sql = "delete from t_book where id=?";
            int update = jdbcTemplate.update(sql, id);
            System.out.println(update);
        }
    
        @Override
        public int queryCount() {
          
          
            String sql = "select count(*) from t_book";
            Integer count = jdbcTemplate.queryForObject(sql, Integer.class);
            return count;
        }
    
        @Override
        public Book queryBookById(int id) {
          
          
            String sql = "select id bookId,name bookName,price bookPrice from t_book where id=?";
            Book book = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<Book>(Book.class), id);
            return book;
        }
    
        @Override
        public List<Book> queryBooks() {
          
          
            String sql = "select id bookId,name bookName,price bookPrice from t_book";
            List<Book> bookList = jdbcTemplate.query(sql, new BeanPropertyRowMapper<Book>(Book.class));
            return bookList;
        }
    
        @Override
        public void batchAddBook(List<Object[]> books) {
          
          
            String sql = "insert into t_book set id=?,name=?,price=?";
            int[] ints = jdbcTemplate.batchUpdate(sql, books);
            System.out.println(ints);
        }
    
        @Override
        public void batchUpdateBook(List<Object[]> books) {
          
          
            String sql = "update t_book set name=?,price=? where id=?";
            int[] ints = jdbcTemplate.batchUpdate(sql, books);
            System.out.println(ints);
        }
    
        @Override
        public void batchDeleteBook(List<Object[]> args) {
          
          
            String sql = "delete from t_book where id=?";
            int[] ints = jdbcTemplate.batchUpdate(sql, args);
            System.out.println(ints);
        }
    }
    
    
    @Service
    public class BookService {
          
          
        @Autowired
        private BookDao bookDao = new BookDaoImpl();
        //添加图书
        public void add(Book book){
          
          
            bookDao.add(book);
        }
        //修改图书
        public void update(Book book){
          
          
            bookDao.update(book);
        }
        //删除图书
        public void delete(Integer id){
          
          
            bookDao.delete(id);
        }
        //查询数量
        public int queryCount(){
          
          
            return bookDao.queryCount();
        }
        //查询图书
        public Book queryBookById(Integer id){
          
          
            return bookDao.queryBookById(id);
        }
        //查询所有图书
        public List<Book> queryBooks(){
          
          
            return bookDao.queryBooks();
        }
        //批量添加图书
        public void batchAddBook(List<Object[]> books){
          
          
            bookDao.batchAddBook(books);
        }
        //批量修改图书
        public void batchUpdateBook(List<Object[]> books){
          
          
            bookDao.batchUpdateBook(books);
        }
        //批量删除图书
        public void batchDeleteBook(List<Object[]> args){
          
          
            bookDao.batchDeleteBook(args);
        }
    }
    

5. Transaction management

  • A transaction is the most basic unit of database operation, either succeeds or fails.

  • Typical Scenario: Transfer

  • ACID has four characteristics of transactions: atomicity, consistency, isolation, and durability.

  • There are two ways of Spring transaction management: programmatic transaction management and declarative transaction management. Generally, declarative transaction management is used, and the bottom layer uses AOP principles.

  • There are two ways of declarative transaction management: xml-based configuration and annotation-based, and annotations are generally used.

  • Spring transaction management provides an interface called transaction manager , which provides different implementation classes for different frameworks.

    image-20210802191449867

    For database interaction using JdbcTemplate, use the DataSourceTransactionManager implementation class. If you integrate the Hibernate framework, use the HibernateTransactionManager implementation class, depending on the specific situation.

(1) Annotations implement declarative transaction management:

<!-- 数据库连接池 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
      destroy-method="close">
    <property name="url" value="jdbc:mysql://localhost:3306/book" />
    <property name="username" value="root" />
    <property name="password" value="000000" />
    <property name="driverClassName" value="com.mysql.jdbc.Driver" />
</bean>

<!--创建JdbcTemplate对象-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    <!--注入数据库连接池-->
    <property name="dataSource" ref="dataSource"></property>
</bean>

<!--创建事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
</bean>

<!--开启事务注解-->
<tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>

Add the transaction annotation @Transactional on the service class or the method of the service class

  • If @Transactional is added to the class, all methods in this class will add transactions.
  • If it is only added on the method, only add the transaction for this method.
@Service
@Transactional
public class UserService {
    
    

Parameter configuration for declarative transaction management:

  1. propagation : transaction propagation behavior, there are 7 types in total, this one is not very clear

  2. isolation : transaction isolation level

    There are three reading problems: dirty reads, non-repeatable reads, and virtual reads (phantom reads).

    Set the isolation level to solve the read problem:

    dirty read non-repeatable read virtual reading
    READ UNCOMMITED (read uncommitted) have have have
    READ COMMITED (read committed) none have have
    REPEATABLE READ (repeatable read) none none have
    SERIALIZABLE (serialization) none none none
  3. timeout : timeout

  • The transaction needs to be committed within a certain period of time, and rolled back after the time exceeds.
  • The default value is -1, and the time is set in seconds.
  1. readOnly : whether to read only
  • The default value is false, which means that it can be queried, and can also be added, deleted or modified.
  • Set to true, only query.
  1. rollbackFor : rollback, set which exceptions occur to roll back the transaction.
  2. noRollbackFor : No rollback, set which exceptions do not perform transaction rollback.
@Service
@Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.READ_COMMITTED)
public class AccountService {
    
    

Fully annotated to implement declarative transaction management:

Configuration class:

@Configuration  //配置类
@ComponentScan(basePackages = "com.oymn.spring5")  //开启组件扫描
@EnableTransactionManagement  //开启事务
public class Config {
    
    

    //创建数据库连接池
    @Bean
    public DruidDataSource getDruidDataSource(){
    
    
        DruidDataSource druidDataSource = new DruidDataSource();
        druidDataSource.setDriverClassName("com.mysql.jdbc.Driver");
        druidDataSource.setUrl("jdbc:mysql://localhost:3306/book");
        druidDataSource.setUsername("root");
        druidDataSource.setPassword("000000");
        return druidDataSource;
    }
    //创建JdbcTemplate对象
    @Bean
    public JdbcTemplate getJdbcTemplate(DataSource dataSource){
    
    
        JdbcTemplate jdbcTemplate = new JdbcTemplate();
        jdbcTemplate.setDataSource(dataSource);
        return jdbcTemplate;
    }
    //创建事务管理器
    @Bean
    public DataSourceTransactionManager getDataSourceTransactionManager(DataSource dataSource){
    
    
        DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
        transactionManager.setDataSource(dataSource);
        return transactionManager;
    }
}
@Service
public class AccountService {
    
    

    @Autowired
    private AccountDao accountDao;

    @Transactional
    public void accountMoney(){
    
    
        accountDao.add();
        //int i=1/0;   //用来模拟转账失败
        accountDao.reduce();
    }
}

(2) XML implements declarative transaction management:

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

<!-- 数据库连接池 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
      destroy-method="close">
    <property name="url" value="jdbc:mysql://localhost:3306/book" />
    <property name="username" value="root" />
    <property name="password" value="000000" />
    <property name="driverClassName" value="com.mysql.jdbc.Driver" />
</bean>

<!--创建JdbcTemplate对象-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    <!--注入数据库连接池-->
    <property name="dataSource" ref="dataSource"></property>
</bean>

<!--创建事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
</bean>

<!--配置事务通知-->
<tx:advice id="txadvice">
    <!--配置事务参数-->
    <tx:attributes>
        <tx:method name="accountMoney" propagation="REQUIRED" />
    </tx:attributes>
</tx:advice>

<!--配置切入点和切面-->
<aop:config>
    <!--配置切入点-->
    <aop:pointcut id="pt" expression="execution(* com.oymn.spring5.Service.*.*(..))"/>
    <!--配置切面-->
    <aop:advisor advice-ref="txadvice" pointcut-ref="pt"/>
</aop:config>

Six, Spring5 new features

1. Comes with log package

  • Spring5 removed Log4jConfigListener, the official recommendation is to use Log4j2

Spring5 integrates Log4j2:

The first step: import jar package

image-20210807143733498

Step 2: Create a log4j2.xml configuration file

<?xml version="1.0" encoding="UTF-8"?>
<!--日志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL -->
<!--Configuration后面的status用于设置log4j2自身内部的信息输出,可以不设置,当设置成trace时,可以看到log4j2内部各种详细输出-->
<configuration status="INFO">
    <!--先定义所有的appender-->
    <appenders>
        <!--输出日志信息到控制台-->
        <console name="Console" target="SYSTEM_OUT">
            <!--控制日志输出的格式-->
            <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
        </console>
    </appenders>
    <!--然后定义logger,只有定义了logger并引入的appender,appender才会生效-->
    <!--root:用于指定项目的根日志,如果没有单独指定Logger,则会使用root作为默认的日志输出-->
    <loggers>
        <root level="info">
            <appender-ref ref="Console"/>
        </root>
    </loggers>
</configuration>

2. @Nullable annotation

  • The @Nullable annotation can be used on methods, properties, and parameters, indicating that the return value of the method can be empty, the property can be empty, and the parameter can be empty.

    @Nullable     //表示方法返回值可以为空
    public int getId();
    
    @Nullable     //表示参数可以为空
    public void setId(@Nullable int Id);
    
    @Nullable     //表示属性可以为空
    public int id;
    

3. Support functional style programming

This is because java8 has added lamda expressions

@Test
public void test() {
    
    
    //1 创建 GenericApplicationContext 对象
    GenericApplicationContext context = new GenericApplicationContext();
    //2 调用 context 的方法对象注册
    context.refresh();
    context.registerBean("user1",User.class,() -> new User());
    //3 获取在 spring 注册的对象
    // User user = (User)context.getBean("com.atguigu.spring5.test.User");
    User user = (User)context.getBean("user1");
    System.out.println(user);
}

4. Support the integration of JUnit5

(1) Integrate JUnit4:

The first step: import jar package

image-20210807181007790

Step 2: Create a test class and use annotations to complete it

@RunWith(SpringJUnit4ClassRunner.class) //单元测试框架
@ContextConfiguration("classpath:bean4.xml") //加载配置文件
public class JUnitTest {
    
    

    @Autowired
    public User user;

    @Test
    public void test(){
    
    
        System.out.println(user);
    }
}

bean4.xml:

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

By using the @ContextConfiguration annotation, the test method does not need to get the object through the context every time, which is more convenient.

ApplicationContext context = new ClassPathXmlApplicationContext("bean2.xml");
BookService bookService = context.getBean("bookService",BookService.class);

(2) Integrate JUnit5:

image-20210807212940977

5. Webflux

Guess you like

Origin blog.csdn.net/OYMNCHR/article/details/120077303