Spring learning day3: AOP, use of JdbcTemplate in spring

Posted by Kevin3374 on Thu, 30 Dec 2021 19:59:34 +0100

1.AOP

1.1 what is AOP

In the software industry, AOP is the abbreviation of Aspect Oriented Programming, which means: Aspect Oriented Programming through precompiler
Dynamic agent is a technology to realize the unified maintenance of program functions. AOP is the continuation of OOP, a hot spot in software development, an important content in Spring framework, and a derivative paradigm of functional programming. AOP can isolate each part of business logic, reduce the coupling between each part of business logic, improve the reusability of program, and improve the efficiency of development.

To understand aspect programming, you need to understand what aspect is first. Divide a watermelon into two parts with a knife, and the cut is the cut surface; For cooking, the pot and stove work together to complete cooking. The pot and stove are cut noodles. In web hierarchy design, web layer - > gateway layer - > service layer - > data layer, and each layer is also an aspect. In programming, there are aspects between objects, methods, and modules.

When we do activities, we usually check the effectiveness of each interface (start, end, etc.) and whether the interface requires user login.

According to normal logic, we can do this.

The problem is that the number of interfaces requires code copies. For a "lazy man", this is intolerable. OK, propose a public method, and each interface calls this interface. There's a bit of slicing here.  

There is also a problem. Although I don't have to copy the code every time, each interface must call this method. So there is the concept of facet. I inject the method into a certain place (tangent point) of the interface call.

There is also a problem. Although I don't have to copy the code every time, each interface must call this method. So there is the concept of facet. I inject the method into a certain place (tangent point) of the interface call.

In this way, the interface only needs to care about the specific business, and does not need to pay attention to other logic or processing not concerned by the interface.
In the red box, it is aspect oriented programming.

1.2 what can AOP do

1. It is to help us reduce the writing of repeated code, so as to improve readability and development efficiency

2. Enhance the program without modifying the source code

3.AOP can perform permission verification, logging, performance monitoring and transaction control

1.3 bottom layer implementation

AOP depends on IOC. In AOP, a proxy class is used to wrap the target class, intercept the method execution of the target class in the proxy class, and weave auxiliary functions. When the Spring container is started, a proxy class bean is created to replace the target class and register it in the IOC, so that the target class instance injected into the application code is actually an instance of the proxy class corresponding to the target class, that is, the proxy class generated by the target class is processed using AOP.

Agency mechanism:

The underlying layer of Spring's AOP uses two proxy mechanisms:

JDK dynamic proxy: generate proxy for classes that implement interfaces  

Cglib's dynamic proxy: generate proxy for classes that do not implement interfaces The underlying bytecode enhancement technology is applied to generate subclass objects of the current class

1.4 AOP related terms

  • Joinpoint: the so-called connection point refers to those intercepted points. In spring, these points refer to methods because

spring only supports method type join points  

  • Advice: the so-called notification means that what needs to be done after intercepting the Joinpoint is notification The notice is divided into pre notice and pre notice

Notification, post notification, exception notification, final notification, surround notification (functions to be completed in all aspects)

  • Pointcut: the so-called pointcut refers to the definition of which joinpoints we want to intercept
  • Introduction: introduction is a special notice. Without modifying the class code, introduction can be run in

Expect to dynamically add some methods or Field for the class  

  • Target: the target object of the proxy
  • Weaving: refers to the process of applying enhancements to the target object to create a new proxy object. spring uses dynamic proxy

While AspectJ adopts compile time weaving and class loading in time weaving

  • Proxy: after a class is enhanced by AOP weaving, a resulting proxy class is generated
  • Aspect: a combination of pointcuts and notifications (Introductions)

1.5 how to use AOP

1. Dynamic agent

package com.tledu.dao.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class DynamicProxy implements InvocationHandler {
    private Object obj;
    public DynamicProxy(Object obj){
        this.obj = obj;
    }

    /**
     * @param proxy  Proxy object
     * @param method Proxy method
     * @param args   Method parameters
     * @return Method
     * @throws Throwable abnormal
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //Pre operation
        before(method);
        method.invoke(obj,args);
        //Post operation
        after(method);
        return null;
    }

    private void before(Method method) {
        System.out.println(method.getName()+" Start call");
    }
    private void after(Method method) {
        System.out.println(method.getName()+" End of call");
    }
}

test

public static void main(String[] args) {
    UserDaoImpl userDao = new UserDaoImpl();
     /**
      The first parameter: the class parser of the real object
      The second parameter: the implemented interface array
      The third parameter: when the proxy method is called, the method will be assigned to this parameter
     */
    IUserDao iu = (IUserDao) Proxy.newProxyInstance(userDao.getClass().getClassLoader(),
            userDao.getClass().getInterfaces(),new DynamicProxy(userDao));
    User u = new User();
    u.setId(3);
    u.setName("aaa");
    iu.add(u);
}

newProxyInstance, the method has three parameters:

Loader: which class loader is used to load the proxy object

interfaces: the interface that the dynamic proxy class needs to implement

InvocationHandler: create a proxy by passing in the object to be proxy. When the dynamic proxy method is executed, it will call the invoke method in the create proxy class to execute

be careful:

The principle of JDK dynamic proxy is to create a new class with the incoming interface according to the defined rules. This is why when using dynamic proxy, you can only use the interface reference to point to the proxy, but not the incoming class reference to execute the dynamic class.

2. Annotation method

It's OK to introduce three again before IOC, because Spring's AOP is developed based on AspectJ

Introducing AOP constraints in configuration files

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
	<!-- introduce AOP constraint -->
	<!-- Use annotation method -->
	<context:annotation-config />
	<context:component-scan base-package="com.tledu" />
	<!-- open AOP Annotation method of -->
	<aop:aspectj-autoproxy />
</beans>

Enable facet support @ EnableAspectJAutoProxy by annotation

AOP class

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class LogInterceptor {
      @Pointcut("execution(public * com.tledu.service..*.add(..))")
      public void myMethod() {
          // Suppose this method is the proxy method
      }
      @Before("myMethod()")
      public void beforeMethod() {
          System.out.println(" execute start");
      }
      @After("myMethod()")
      public void afterMethod() {
          System.out.println(" execute end");
      }
      // Surround, both Before and After, is equivalent to @ Before and @ After being used together
      @Around("myMethod()")
      public void aroundMethod(ProceedingJoinPoint pjp) throws Throwable {
      // @Around can also be used with @ Before and @ After
          System.out.println("around start");
          // Call the proxied method
          pjp.proceed();
          System.out.println("around end");
      }
}

3. XML mode

Import jar package

It is introduced in the same way as annotation

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
    <context:annotation-config/>
    <context:component-scan base-package="com.tledu"/>
    <!--open AOP annotation-->
    <!--<aop:aspectj-autoproxy />-->

    <bean id="logInterceptor" class="com.tledu.aop.LogInterceptor"></bean>
    <aop:config>
        <aop:aspect id="logAspet" ref="logInterceptor">
            <!-- Method of proxy required -->
            <aop:pointcut expression="execution(public * com.tledu.service..*.add(..))"
                          id="pointcut" />
            <!-- Before and after execution -->
            <aop:before method="beforeMethod" pointcut-ref="pointcut" />
            <!-- Or write it like this,So there's no need pointcut Label -->
            <!-- <aop:before method="before" pointcut="execution(public * com.tledu.service..*.add(..))"
          /> -->
            <aop:after method="afterMethod" pointcut-ref="pointcut" />
            <!-- surround,Generally either use around To and use before and after Will not be used together -->
            <aop:around method="aroundMethod" pointcut-ref="pointcut" />
        </aop:aspect>
    </aop:config>

</beans>

AOP class

Same as the annotation, but remove the annotation

import org.aspectj.lang.ProceedingJoinPoint;
public class LogInterceptor {
public void myMethod() {
 // Suppose this method is the proxy method
}
public void before() {
 System.out.println(" execute start");
}
public void after() {
 System.out.println(" execute end");
}
// Surround, both Before and After, is equivalent to @ Before and @ After being used together
public void aroundMethod(ProceedingJoinPoint pjp) throws Throwable {
 // @Around can also be used with @ Before and @ After
 System.out.println("around start");
 // Call the proxied method
 pjp.proceed();
 System.out.println("around end");
}
}

Test class

public static void main(String[] args) {
    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
            "applicationContext.xml");
    UserService userService = context.getBean(UserService.class);
    User u = new User();
    u.setName("Li Si");
    userService.add(u);
}

2. Use of JDBC template in spring

2.1 what is a jdbc Template

It is an object provided in the spring framework and a simple encapsulation of the original Jdbc API object. The spring framework provides us with many operation template classes.

Operation of relational data:

JdbcTemplate

HibernateTemplate

To operate nosql database:

RedisTemplate

Operation message queue:

JmsTemplate

Our protagonist today is spring JDBC In jar, in addition to importing the jar package, we also need to import a spring-tx.jar (which is transaction related)

2.2 creation of JDBC template object

We can refer to its source code to explore:

public JdbcTemplate() {
}
public JdbcTemplate(DataSource dataSource) {
    setDataSource(dataSource);
    afterPropertiesSet();
}
public JdbcTemplate(DataSource dataSource, boolean lazyInit) {
    setDataSource(dataSource);
    setLazyInit(lazyInit);
    afterPropertiesSet();
}

In addition to the default constructor, you need to provide a data source. Since there is a set method, we can configure these objects in the configuration file according to the dependency injection we learned before

2.3 configuring data sources

1. Environmental construction

 2. Configuration file import constraints

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
 
</beans>

3. Configure DBCP data source

 

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
    <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
    <property name="url" value="jdbc:mysql://localhost:3306/ssm"></property>
    <property name="username" value="root"></property>
    <property name="password" value="root"></property>
</bean>

The spring framework also provides a built-in data source. We can also use spring's built-in data source, which is located in spring JDBC Jar

 <!-- Configure data sources-->
 <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
        <property name="url" value="jdbc:mysql://localhost:3306/ssm"></property>
        <property name="username" value="root"></property>
        <property name="password" value="root"></property>
</bean>

Dou E can choose one of the above two

2.4 addition, deletion, modification and query

1. Configure jdbc Template

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">
 
 
<!-- Configure a database operation template: JdbcTemplate -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    <property name="dataSource" ref="dataSource"></property>
</bean>
 
<!-- Configure data sources -->
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
    <property name="url" value="jdbc:mysql://localhost:3306/ssm"></property>
    <property name="username" value="root"></property>
    <property name="password" value="root"></property>
</bean>
</beans>

2. Basic usage

public static void main(String[] args) {
    DriverManagerDataSource ds = new DriverManagerDataSource();
    ds.setDriverClassName("com.mysql.jdbc.Driver");
    ds.setUrl("jdbc:mysql://localhost:3306/ssm");
    ds.setUsername("root");
    ds.setPassword("root");

    //1. Create a JdbcTemplate object
    JdbcTemplate jt = new JdbcTemplate();
    //Set data source for jt
    jt.setDataSource(ds);
    //2. Perform the operation
    jt.execute("insert into t_user(username,password)values('ccc','aaa')");
 }

3. Basic usage after spring integration

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
JdbcTemplate jt = (JdbcTemplate) context.getBean("jdbcTemplate");
//jdbcTemplate.execute("insert into t_user(username,password)values('zhang Meiling ',' 888 '));
// Query all
List<User> accounts = jt.query("select * from t_user",new UserRowMapper());
for (User account : accounts) {
    System.out.println(account);
}
System.out.println("--------");
User user = jt.queryForObject("select * from t_user where id = ?",new BeanPropertyRowMapper<User>(User.class),1);
System.out.println(user);

System.out.println("--------");
//Return the total number of entries with id greater than 3
Integer count  = jt.queryForObject("select count(*) from t_user where id > ?", Integer.class, 3);
System.out.println(count);
//Multi condition query, fuzzy query
List<User> ulist = jt.query("select * from t_user where t_user.username like ? and nickname like ? ",new UserRowMapper(),new Object[]{"%a%","%a%"});
System.out.println(ulist.size());
for (User user1 : ulist) {
    System.out.println(user1);
}

Define User's encapsulation policy

public class UserRowMapper implements RowMapper<User> {

    @Override
    public User mapRow(ResultSet rs, int i) throws SQLException {
        User u = new User();
        u.setId(rs.getInt("id"));
        u.setUsername(rs.getString("username"));
        return u;
    }
}

2.5 add jdbc Template to Dao layer

1. Entity class

public class User {
    private Integer id;
    private String username;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

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

2. Define IUserDao interface

public interface IUserDao {
    //Add a user message
    void add(User user);
    //Delete a piece of data according to id
    void delete(Integer id);
    //Modify a piece of data
    void update(User user);
    //Query user information list according to criteria
    List<User> getUserList(User user);
    //Query a piece of data by id
    User getUserById(Integer id);
    //Get the total number of entries
    Integer getListCount();
}

3. Add JDBC template in UserDaoImpl implementation class

public class UserDaoImpl implements IUserDao {

    private JdbcTemplate jdbcTemplate;

    @Override
    public void add(User user) {
        String sql = " insert into t_user(username) values('"+user.getUsername()+"') ";
        jdbcTemplate.execute(sql);
    }

    @Override
    public void delete(Integer id) {
        String sql = "delete from t_user where id = "+id+"";
        jdbcTemplate.execute(sql);
    }

    @Override
    public void update(User user) {
        String sql = "update t_user set username = '"+user.getUsername()+"' where id = "+user.getId()+"";
        jdbcTemplate.execute(sql);
    }

    @Override
    public List<User> getUserList(User user) {
        String sql = " select * from t_user where 1=1 ";
        if(user.getUsername()!=null){
            sql += "and username like '%"+user.getUsername()+"%'";
        }
        return jdbcTemplate.query(sql,new UserRowMapper());
    }

    @Override
    public User getUserById(Integer id) {
        String sql = " select * from t_user where id = "+id+" ";
        return jdbcTemplate.queryForObject(sql,new UserRowMapper());
    }

    @Override
    public Integer getListCount() {
        String sql = "select count(*) from t_user where username like '%beautiful%'";
        return jdbcTemplate.queryForObject(sql,Integer.class);
    }

    public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }
}

4. Inject JDBC template into UserDaoImpl in the 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
        http://www.springframework.org/schema/beans/spring-beans.xsd">
 
<!-- Configure the persistence layer of the account -->
<bean id="accountDao" class="com.tledu.dao.impl.UserDaoImpl">
    <property name="jdbcTemplate" ref="jdbcTemplate"></property>
</bean>
 
<!-- Configure a database operation template: JdbcTemplate -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    <property name="dataSource" ref="dataSource"></property>
</bean>
 
<!-- Configure data sources -->
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
    <property name="url" value="jdbc:mysql://localhost:3306/ssm"></property>
    <property name="username" value="root"></property>
    <property name="password" value="root"></property>
</bean>
</beans>

5. Test

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
JdbcTemplate jt = (JdbcTemplate) context.getBean("jdbcTemplate");
//jdbcTemplate.execute("insert into t_user(username,password)values('zhang Meiling ',' 888 '));
// Query all
List<User> accounts = jt.query("select * from t_user",new UserRowMapper());
for (User account : accounts) {
    System.out.println(account);
}
System.out.println("--------");
//Query a piece of data by id
User user = jt.queryForObject("select * from t_user where id = ?",new BeanPropertyRowMapper<User>(User.class),1);
System.out.println(user);

System.out.println("--------");
//Return the total number of entries with id greater than 3
Integer count  = jt.queryForObject("select count(*) from t_user where id > ?", Integer.class, 3);
System.out.println(count);
//Multi condition query, fuzzy query
List<User> ulist = jt.query("select * from t_user where t_user.username like ? and nickname like ? ",new UserRowMapper(),new Object[]{"%a%","%a%"});
System.out.println(ulist.size());
for (User user1 : ulist) {
    System.out.println(user1);
}

6. Problems

Is there any problem with this method?

answer:

There's a small problem. When we have many Daos, each dao has some repetitive code. Here is the duplicate code:

private JdbcTemplate jdbcTemplate;

public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {

this.jdbcTemplate = jdbcTemplate;

}

7. Inherit JdbcDaoSupport

JdbcDaoSupport is a class provided to us by the spring framework. A JdbcTemplate object is defined in this class, which can be obtained and used directly. However, to create this object, you need to provide it with a data source:

The specific source code is as follows:

public abstract class JdbcDaoSupport extends DaoSupport {
//Define object
private JdbcTemplate jdbcTemplate;
//The set method injects the data source to determine whether it is injected. After injection, a JdbcTemplate is created
public final void setDataSource(DataSource dataSource) {
    if (this.jdbcTemplate == null || dataSource != this.jdbcTemplate.getDataSource()) {
    //If a data source is provided, create a JdbcTemplate
    this.jdbcTemplate = createJdbcTemplate(dataSource);
    initTemplateConfig();
    }
}
//Create a JdcbTemplate using a data source
protected JdbcTemplate createJdbcTemplate(DataSource dataSource) {
    return new JdbcTemplate(dataSource);
}
//Of course, we can also inject the JdbcTemplate object
public final void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
    this.jdbcTemplate = jdbcTemplate;
    initTemplateConfig();
}
//Use the getJdbcTmeplate method to obtain the operation template object
public final JdbcTemplate getJdbcTemplate() {
return this.jdbcTemplate;
}

8. UserDaoImpl implementation class inherits JdbcDaoSupport

public class UserDaoImpl2 extends JdbcDaoSupport implements IUserDao {

    //private JdbcTemplate jdbcTemplate;

    @Override
    public void add(User user) {
        String sql = " insert into t_user(username) values('"+user.getUsername()+"') ";
        super.getJdbcTemplate().execute(sql);
    }

    @Override
    public void delete(Integer id) {
        String sql = "delete from t_user where id = "+id+"";
        super.getJdbcTemplate().execute(sql);
    }

9. In ApplicationContext Inject dataSource into UserDaoImpl in XML

<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource">
    <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
    <property name="url" value="jdbc:mysql://localhost:3306/ssm"></property>
    <property name="username" value="root"></property>
    <property name="password" value="root"></property>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    <property name="dataSource" ref="dataSource"></property>
</bean>
<bean id="userDao" class="com.tledu.dao.impl.UserDaoImpl2">
    <!--<property name="jdbcTemplate" ref="jdbcTemplate"></property>-->
    <property name="dataSource" ref="dataSource"></property>
</bean>

10. Test

public class UserDaoImplTest2 {

    private ApplicationContext context;

    @Before
    public void before(){
        context = new ClassPathXmlApplicationContext("applicationContext.xml");
    }
    @Test
    public void add(){
        IUserDao userDao = context.getBean(UserDaoImpl2.class);
        User user = new User();
        user.setUsername("JoSon");
        userDao.add(user);
    }
    @Test
    public void delete(){
        IUserDao userDao = context.getBean(UserDaoImpl2.class);
        userDao.delete(26);
    }

Topics: Java Spring Spring Boot