Spring getting started notes

Chapter 1 spring overview

1.1 spring overview

1.1. 1 what is spring

Spring is a lightweight open source framework for layered Java Se / EE applications, IOC (inverse of control) and AOP (aspect oriented programming: Aspect Oriented Programming) as the kernel, it provides many enterprise application technologies such as presentation layer spring MVC, persistence layer spring JDBC and business layer transaction management. It can also integrate many world-famous third-party frameworks and class libraries, and gradually become the most used open source framework for Java EE enterprise applications.

1.1. 2 advantages of spring

1.1. 3. Spring architecture

Chapter II concept and function of IOC

2.1 program coupling and decoupling

The concepts of coupling and decoupling were also learned in the software engineering class last semester. Here is a review of them.

2.1. 1 what is program coupling

Coupling, also known as coupling degree, is a measure of the degree of correlation between modules. The strength of coupling depends on the complexity of the interface between modules, the way to call modules and how much data is transmitted through the interface. The coupling degree between modules refers to the dependency relationship between modules, including control relationship, call relationship and data transfer relationship. The more connections between modules, the stronger the coupling, and the worse the independence (reducing the coupling can improve the independence). Coupling exists in various fields, not unique in software design, but we only discuss coupling in software engineering.

In software engineering, coupling refers to the dependency between objects. The higher the coupling between objects, the higher the maintenance cost. Therefore, the design of objects should minimize the coupling between classes and components. In software design, coupling and cohesion are usually used as the criteria to measure the degree of module independence. A criterion for dividing modules is high cohesion and low coupling.

It is classified as follows:

(1) Content coupling. When a module directly modifies or operates the data of another module, or a module transfers to another module without passing through the normal entry, such coupling is called content coupling. Content coupling is the highest degree of coupling and should be avoided.

(2) Common coupling. Two or more modules jointly reference a global data item, which is called common coupling. In a structure with a large number of common coupling, it is very difficult to determine which module assigns a specific value to the global variable.

(3) External coupling: when a group of modules access the same global simple variable instead of the same global data structure, and the information of the global variable is not transmitted through the parameter table, it is called external coupling.

(4) Control coupling. One module transmits a control signal to another module through the interface, and the module receiving the signal performs appropriate actions according to the signal value. This coupling is called control coupling.

(5) Tag coupling. If a module a passes a common parameter to two modules B and C through the interface, it is said that there is a tag coupling between modules B and C.

(6) Data coupling. If modules transfer data through parameters, it is called data coupling. Data coupling is the lowest form of coupling. This type of coupling generally exists in the system, because in order to complete some meaningful functions, it is often necessary to take the output data of some modules as the input data of others.

(7) Indirect coupling. There is no direct relationship between the two modules, and the relationship between them is completely realized through the control and call of the main module.

Summary:

Coupling is an important factor affecting software complexity and design quality. In design, we should adopt the following principles: if there must be coupling between modules, use data coupling as much as possible, use less control coupling, limit the scope of public coupling and avoid content coupling as much as possible.

Cohesion and coupling

Cohesion marks the tightness of each element in a module. It is a natural extension of the concept of information concealment and localization. Cohesion is to measure the relationship within a module from a functional perspective. A good cohesion module should do exactly one thing. It describes the functional connections within the module. Coupling is a measure of the interconnection between modules in software structure. The strength of coupling depends on the complexity of the interface between modules, the points entering or accessing a module and the data passing through the interface. The program pays attention to low coupling and high cohesion. That is, the elements in the same module should be highly close, but the interdependence between modules is not so close.

Cohesion and coupling are closely related. A module with high coupling with other modules means low cohesion, while a module with high cohesion means low coupling with other modules. In software design, we should strive to achieve high cohesion and low coupling.

In our development, some dependencies are necessary, and some dependencies can be removed by optimizing the code.

See the following example code:

//账户的业务层实现类
public class AccountServiceImpl implements AccountService {
	private AccountDao accountDao = new AccountDaoImpl();
}

The above code indicates:

The business layer calls the persistence layer, and at this time, the business layer depends on the interface and implementation class of the persistence layer. If there is no persistence layer implementation class at this time, the compilation will not pass. This compile time dependency should be eliminated in our development. We need to optimize the code to solve.

For another example, when using JDBC to register drivers, why don't we use the register method of drivermanager instead of class How forname?

public class JdbcDemo {
	public static void main(String[] args) throws Exception{
		//1.注册驱动 
		//DriverManager.registerDriver(new com.MysqL.jdbc.Driver()); 			
		Class.forName("com.MysqL.jdbc.Driver");
		//2.获取连接 
		//3.获取预处理 sql 语句对象 
		//4.获取结果集 
		//5.遍历结果集 
	}
} 

The reason is:

Our class depends on the specific driver class of the database (MySQL). If we change the database brand (such as Oracle), we need to modify the source code to re drive the database. Obviously, this is not what we want.

2.1. 2 ideas for solving program coupling

When we use JDBC, we register drivers through reflection. The code is as follows:

Class. forName("com.MysqL.jdbc.Driver");// This is just a string

The advantage of this is that our classes no longer rely on specific driver classes. At this time, even if the driver jar package of MySQL is deleted, it can still be compiled (don't think about running. It can't run successfully without a driver).

At the same time, a new problem arises. The fully qualified class name string driven by MySQL is written dead in the Java class. Once it needs to be changed, it still needs to modify the source code.

It is also easy to solve this problem by using the configuration file configuration.

2.1. 3 plant mode decoupling

In the actual development, we can use the configuration file to configure the objects of the three layers. When the server application is started to load, let the methods in a class create these objects and coexist by reading the configuration file. In the next use, just take it directly.

Then, the class that reads the configuration file, creates and obtains three-tier objects is the factory.

2.1. 4 inversion of control

There are two problems in the idea of plant mode decoupling:

1. Where to?

Analysis: because we are many objects, we must find a collection to save. At this time, there are maps and lists to choose from. Whether we choose map or list depends on whether we have search requirements. If you need to find, select map.

So our answer is to create a map to store three-tier objects when the application is loaded. We call this map a container.

2. What is a factory?

The factory is the class responsible for getting the specified object from the container. At this time, the way we get objects has changed.

original:

When we get objects, we all use new. It's proactive.

Now?

When we get objects, we need to follow the factory at the same time. There is a factory to find or create objects for us. Is passive.

The idea of acquiring objects by passive receiving is control inversion, which is one of the cores of spring framework.

Chapter 3 IOC solution coupling using spring

3.1 preliminary preparation of cases

The case we use in this chapter is the dependency resolution of the business layer and persistence layer of the account. Before starting the spring configuration, we need to prepare the environment. Because we use spring to solve dependencies, we don't really need to add, delete, modify and query, so we don't need to write entity classes at this time. And what we use here is a java project, not a Java Web project.

1. In POM Add spring context dependency to XML

2. Create business layer interfaces and implementation classes

public interface AccountService {
	void saveAccount();
}

public class AccoutServiceImpl implements AccountService {
	private AccountDao accountDao = new AccountDaoImpl();//此处的依赖关系有待解决
	
	@Override
	public void saveAccount(){
		accountDao.saveAccount();
	}
}

3. Create persistence layer interface and implementation class

public interface AccountDao { void saveAccount(); }

Public class accountdaoimpl implements accountdao {@ override public void saveaccount() {system.out.println ("saved account");}}

3.2 XML based configuration (introductory case) [Master]

1. Create a bean under the resource of Maven project xml

To import constraints to a profile:

<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">
	<!-- more bean de@R_419_1292@ns go here -->
</beans>

2. Let spring manage resources and configure service and Dao in the configuration file

<!-- bean 标签:用于配置让 spring 创建对象,并且存入 ioc 容器之中 
		id 属性:对象的唯一标识。 
		class 属性:指定要创建对象的全限定类名 
-->
<!-- 配置 service -->    
<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl"></bean> 
<!-- 配置 dao -->
<bean id="accountDao" class="com.itheima.dao.impl.AccountDaoImpl"></bean>

Test whether the configuration is successful

//模拟一个表现层
public class Client {
	public static void main(String[] args) {
		//1.使用ApplicationContext接口,就是在获取spring容器
		ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
		//2.根据bean的id获取对象
		AccountService as = (AccountService) ac.getBean("accountService");
		System.out.println(as);
		AccountDao ad = (AccountDao) ac.getBean("accountDao");
		System.out.println(ad);
	}
}

Normal output of operation results

3.3 spring XML based IOC details [Master]

3.3. 1. Class structure diagram of factory in spring

3.3. 1.1 difference between beanfactory and ApplicationContext

Beanfactory is the top-level interface in the spring container.

ApplicationContext is its sub interface.

Difference between beanfactory and ApplicationContext:

3.3. 1.2 implementation class of ApplicationContext interface

3.3. 2 bean label and management object details in IOC

3.3. 2.1 bean Tags

effect:

Properties:

3.3. 2.2 scope and life cycle of beans

Singleton object: scope = "Singleton"

An application has only one instance of an object. Its scope is the entire reference.

Life cycle:

Multi instance object: scope = "prototype"

Each time an object is accessed, the object instance is recreated.

Life cycle:

3.3. 2.3 three methods of instantiating beans

The first way: use the default parameterless constructor

 <!--在默认情况下: 
  它会根据默认无参构造函数来创建类对象。如果 bean 中没有默认无参构造函数,将会创建失败。  
 --> 
<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl"/> 

The second way: Spring manages the static factory - use the static factory method to create objects

//模拟一个静态工厂,创建业务层实现类
public class StaticFactory {
	public static AccountService createAccountService() {
		return new AccountServiceImpl();
	}
}
<!-- 此种方式是: 
  使用 StaticFactory 类中的静态方法 createAccountService 创建对象,并存入 spring 容器 
  id 属性:指定 bean 的 id,用于从容器中获取 
  class 属性:指定静态工厂的全限定类名 
  factory-method 属性:指定生产对象的静态方法 
--> 
<bean id="accountService"  
   class="com.itheima.factory.StaticFactory"  
   factory-method="createAccountService"></bean> 

The third way: Spring manages the instance factory - create objects using the instance factory method

/** 
 * 模拟一个实例工厂,创建业务层实现类 
 * 此工厂创建对象,必须现有工厂实例对象,再调用方法  
 */
public class InstanceFactory {
	public AccountService createAccountSerivce() {
		return new AccountServiceImpl();
	}
}

<!-- 此种方式是: 
     先把工厂的创建交给 spring 来管理。 
     然后在使用工厂的 bean 来调用里面的方法 
     factory-bean 属性:用于指定实例工厂 bean 的 id。 
     factory-method 属性:用于指定实例工厂中创建对象的方法。 
--> 
 <bean id="instancFactory" class="com.itheima.factory.InstanceFactory"></bean>
 <bean id="accountService"  
    factory-bean="instancFactory"  
    factory-method="createAccountService"></bean> 

3.3. 3 spring dependency injection

3.3. 3.1 concept of dependency injection

Dependency injection: dependency injection. It is the concrete implementation of the spring framework core IOC.

When writing our program, we handed over the creation of objects to spring through control inversion, but there can be no dependency in the code. IOC decoupling only reduces their dependencies, but it will not eliminate them. For example, our business layer will still call the methods of the persistence layer.

After using spring, the dependency between the business layer and the persistence layer can be maintained by spring. Simply put, it means waiting for the framework to transfer the persistence layer object to the business layer without getting it ourselves.

3.3. 3.2 constructor injection

As the name suggests, it uses the constructor in the class to assign values to member variables. Note that the assignment operation is not done by ourselves, but through configuration, let the spring framework inject for us. The specific codes are as follows:

public class AccountServiceImpl1 implements AccountService {
	private String name;
	private Integer age;
	private Date birthday;

	public AccountServiceImpl(String name,Integer age,Date birthday) {
		this.name = name;
		this.age = age;
		this.birthday = birthday;
	}
	
	@Override
	public void saveAccount() {
		System.out.println();
	}
}

<!-- 使用构造函数的方式,给 service 中的属性传值 
	要求: 
		类中需要提供一个对应参数列表的构造函数。 
	涉及的标签: 
		constructor-arg
			属性:
				index:指定参数在构造函数参数列表的索引位置 
				type:指定参数在构造函数中的数据类型 
				name:指定参数在构造函数中的名称     用这个找给谁赋值 
				=======上面三个都是找给谁赋值,下面两个指的是赋什么值的============== 
				value:它能赋的值是基本数据类型和 String 类型 
				ref:它能赋的值是其他 bean 类型,也就是说,必须得是在配置文件中配置过的 bean 
--> 

<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl1">
	<constructor-arg name="name" value="张三"></constructor-arg>
	<constructor-arg name="age" value="18"></constructor-arg> 
	<constructor-agr> name="birthday" ref="Now"></constructor-arg> 
</bean>

<bean id="Now" class="java.util.Date"></bean>

3.3. 3.3 set method injection

As the name suggests, it is to provide a set method in a class that needs to inject members. The specific codes are as follows:

public class AccountServiceImpl2 implements AccountService {
	private String name;
	private Integer age;
	private Date birthday;
	
	public void setName(String name) {
		this.name = name;
	}
	public void setAge(Integer age) {
		this.age = age;
	}
	public void setBirthday(Date birthday) {
		this.birthday = birthday;
	}
	@Override
	public void saveAccount() {
		System.out.println(name+","+age+","+birthday);
	}
}

<!-- 通过配置文件给 bean 中的属性传值:使用 set 方法的方式 
	涉及的标签: 
		property 
			属性: 
				name:找的是类中 set 方法后面的部分 
				ref:给属性赋值是其他 bean 类型的 
				value:给属性赋值是基本数据类型和 string 类型的 
		实际开发中,此种方式用的较多。 
-->
<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl2"> 
	<property name="name" value="test"></property>
	<property name="age" value="21"></property> 
	<property name="birthday" ref="Now"></property> 
</bean> 
<bean id="Now" class="java.util.Date"></bean> 

3.3. 3.4 injecting data using the P namespace (essentially calling the set method)

This method imports the P namespace into XML and uses P: propertyname to inject data. Its essence is still to call the set method in the class to realize the injection function.

Java code (same as set injection):

public class AccountServiceImpl3 implements AccountService {
	private String name;
	private Integer age;
	private Date birthday;
	
	public void setName(String name) {
		this.name = name;
	}
	public void setAge(Integer age) {
		this.age = age;
	}
	public void setBirthday(Date birthday) {
		this.birthday = birthday;
	}
	@Override
	public void saveAccount() {
		System.out.println(name+","+birthday);
	}
}

Configuration file code (constraints to be added P):

<beans xmlns="http://www.springframework.org/schema/beans" 
	   xmlns:p="http://www.springframework.org/schema/p" 
	   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"> 
	<bean id="accountService"  
 		  class="com.itheima.service.impl.AccountServiceImpl3" 
		  p:name="test" p:age="21" p:birthday-ref="Now"/> 
	<bean id="Now" class="java.util.Date"></bean>
</beans>

3.3. 3.5 injection set attributes

As the name suggests, it is to pass values to the collection members in the class. It also uses the method of set injection, but the data types of variables are collections. Here we introduce the injection array, list, set, map and properties. The specific codes are as follows:

public class AccountServiceImpl4 implements AccountService {
	private String[] myStrs;
	private List<String> myList;
	private Set<String> mySet;
	private Map<String,String> myMap;
	private Properties myProps;

	public void setMyStrs(String[] myStrs) {
		this.myStrs = myStrs;
	}
	public void setMyList(List<String> myList) {
		this.myList = myList;
	}
	public void setMySet(Set<String> mySet) {
		this.mySet = mySet; 
 	}
	public void setMyMap(Map<String,String> myMap) {
 		this.myMap = myMap;
	}
	public void setMyProps(Properties myProps) {
		this.myProps = myProps;
	}

	@Override
	public void saveAccount() {
		//省略...
	}
}

<!-- 注入集合数据 
	List 结构的: 
		array,list,set 
	Map 结构的 
		map,entry,props,prop 
-->
<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl"> 
	<!-- 在注入集合数据时,只要结构相同,标签可以互换 --> 
	<!-- 给数组注入数据 --> 
	<property name="myStrs"> 
		<set> 
			<value>AAA</value>
			<value>BBB</value>
			<value>CCC</value>
		</set>
	</property>
	<!-- 注入List集合数据 --> 
	<property name="myList"> 
		<array> 
			<value>AAA</value>
			<value>BBB</value>
			<value>CCC</value>
		</array>
	</property>
	<!-- 注入Set集合数据 --> 
	<property name="mySet"> 
		<list> 
			<value>AAA</value>
			<value>BBB</value>
			<value>CCC</value>
		</list>
	</property>
	<!-- 注入Map数据 --> 
	<property name="myMap"> 
		<props> 
			<prop key="testA">aaa</prop>
			<prop key="testB">bbb</prop>
		</props>
	</property>
	<!-- 注入properties数据 --> 
	<property name="myProps"> 
		<map> 
			<entry key="testA" value="aaa"></entry>
			<entry key="testB">
				<value>bbb</value>
			</entry>
		</map>
	</property>
</bean>

Chapter 4 case: crud of account using IOC of spring

4.1 requirements and technical requirements

Requirement: realize the crud operation of the account

Technical requirements:

4.2 coding

4.2. 1 create database and write entity class

create table account(
  id int primary key auto_increment,name varchar(40),money float
)character set utf8 collate utf8_general_ci; 

insert into account(name,money) values('aaa',1000); 
insert into account(name,money) values('bbb',money) values('ccc',1000); 

//账户的实体类
public class Account implements Serializable {
	private Integer id;
	private String name;
	private Float money;
	//三个属性的getter/setter方法 在此省略
}

4.2. 2 write persistence layer code

//账户的持久层接口
public interface AccountDao {
    /**
     * 查询所有
     * @return
     */
    List<Account> findAllAccount();

    /**
     * 查询一个
     * @return
     */
    Account findAccountById(Integer accountId);

    /**
     * 保存
     * @param account
     */
    void saveAccount(Account account);

    /**
     * 更新
     * @param account
     */
    void updateAccount(Account account);

    /**
     * 删除
     * @param acccountId
     */
    void deleteAccount(Integer acccountId);
}


//账户的持久层实现类
public class AccountDaoImpl implements AccountDao {

    private QueryRunner runner;

    public void setRunner(QueryRunner runner) {
        this.runner = runner;
    }

    @Override
    public List<Account> findAllAccount() {
        try{
            return runner.query("select * from account",new BeanListHandler<Account>(Account.class));
        }catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public Account findAccountById(Integer accountId) {
        try{
            return runner.query("select * from account where id = ? ",new BeanHandler<Account>(Account.class),accountId);
        }catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void saveAccount(Account account) {
        try{
            runner.update("insert into account(name,money)values(?,?)",account.getName(),account.getMoney());
        }catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void updateAccount(Account account) {
        try{
            runner.update("update account set name=?,money=? where id=?",account.getMoney(),account.getId());
        }catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void deleteAccount(Integer accountId) {
        try{
            runner.update("delete from account where id=?",accountId);
        }catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

4.2. 3. Write business layer code

//账户的业务层接口
public interface AccountService {
    /**
     * 查询所有
     * @return
     */
    List<Account> findAllAccount();

    /**
     * 查询一个
     * @return
     */
    Account findAccountById(Integer accountId);

    /**
     * 保存
     * @param account
     */
    void saveAccount(Account account);

    /**
     * 更新
     * @param account
     */
    void updateAccount(Account account);

    /**
     * 删除
     * @param acccountId
     */
    void deleteAccount(Integer acccountId);
}


//账户的业务层实现类
public class AccountServiceImpl implements AccountService{

    private IAccountDao accountDao;

    public void setAccountDao(IAccountDao accountDao) {
        this.accountDao = accountDao;
    }

    @Override
    public List<Account> findAllAccount() {
        return accountDao.findAllAccount();
    }

    @Override
    public Account findAccountById(Integer accountId) {
        return accountDao.findAccountById(accountId);
    }

    @Override
    public void saveAccount(Account account) {
        accountDao.saveAccount(account);
    }

    @Override
    public void updateAccount(Account account) {
        accountDao.updateAccount(account);
    }

    @Override
    public void deleteAccount(Integer acccountId) {
        accountDao.deleteAccount(acccountId);
    }
}

4.2. 4 create and write configuration files

Create a bean under resource xml

The configuration is as follows:

<?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">
    <!-- 配置Service -->
    <bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
        <!-- 注入dao -->
        <property name="accountDao" ref="accountDao"></property>
    </bean>

    <!--配置Dao对象-->
    <bean id="accountDao" class="com.itheima.dao.impl.AccountDaoImpl">
        <!-- 注入QueryRunner -->
        <property name="runner" ref="runner"></property>
    </bean>

    <!--配置QueryRunner-->
    <bean id="runner" class="org.apache.commons.dbutils.QueryRunner" scope="prototype">
        <!--注入数据源-->
        <constructor-arg name="ds" ref="dataSource"></constructor-arg>
    </bean>

    <!-- 配置数据源 -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <!--连接数据库的必备信息-->
        <property name="driverClass" value="com.MysqL.jdbc.Driver"></property>
        <property name="jdbcUrl" value="jdbc:MysqL://localhost:3306/eesy"></property>
        <property name="user" value="root"></property>
        <property name="password" value="root"></property>
    </bean>
</beans>

4.3 test cases

4.3. 1 test class code

public class AccountServiceTest {

    @Test
    public void testFindAll() {
        //1.获取容器
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        //2.得到业务层对象
        IAccountService as = ac.getBean("accountService",IAccountService.class);
        //3.执行方法
        List<Account> accounts = as.findAllAccount();
        for(Account account : accounts){
            System.out.println(account);
        }
    }

    @Test
    public void testFindOne() {
        //1.获取容器
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        //2.得到业务层对象
        IAccountService as = ac.getBean("accountService",IAccountService.class);
        //3.执行方法
        Account account = as.findAccountById(1);
        System.out.println(account);
    }

    @Test
    public void testSave() {
        Account account = new Account();
        account.setName("test");
        account.setMoney(12345f);
        //1.获取容器
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        //2.得到业务层对象
        IAccountService as = ac.getBean("accountService",IAccountService.class);
        //3.执行方法
        as.saveAccount(account);

    }

    @Test
    public void testUpdate() {
        //1.获取容易
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        //2.得到业务层对象
        IAccountService as = ac.getBean("accountService",IAccountService.class);
        //3.执行方法
        Account account = as.findAccountById(4);
        account.setMoney(23456f);
        as.updateAccount(account);
    }

    @Test
    public void testDelete() {
        //1.获取容易
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        //2.得到业务层对象
        IAccountService as = ac.getBean("accountService",IAccountService.class);
        //3.执行方法
        as.deleteAccount(4);
    }
}

4.3. 2 analyze the problems in the test

Through the above test classes, we can see that each test method re obtains the core container of spring, resulting in unnecessary duplicate code and increasing our development workload. This situation should be avoided in development.

Of course, we can define the acquisition of containers into classes. For example:

public class AccountServiceTest { 
	private ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml"); 
	private AccountService as = ac.getBean("accountService",AccountService.class); 
}

Although this method can solve the problem, we still need to write our own code to get the container. Can you write test methods directly when testing without manual coding to obtain containers? The answer can be found in Chapter 6.

Chapter 5 annotation based IOC configuration

5.1 clear: write at the top

Annotation configuration and XML configuration have the same functions to reduce the coupling between programs. But the configuration form is different.

Each company has different usage habits about whether to use XML or annotations in actual development. Therefore, we need to master both configuration methods.

When learning annotation configuration, use the case in the previous chapter to change the XML configuration content of spring to use annotation for gradual implementation.

5.2 using annotations to configure managed resources

@Service("accountService")
public class AccountServiceImpl implements AccountService{

    @Autowired
    private IAccountDao accountDao;
	//省略...
}

@Repository("accountDao")
public class AccountDaoImpl implements IAccountDao {

    @Autowired
    private QueryRunner runner;
	//省略...
}

5.3 modify bean XML enables support for annotations

Note: when integrating based on annotations, you need to import one more constraint under the context namespace when importing 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"
       xmlns:context="http://www.springframework.org/schema/context"
       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">

    <!-- 告知spring在创建容器时要扫描注解的包 -->
    <context:component-scan base-package="com.itheima"></context:component-scan>
    <!--配置QueryRunner-->
    <bean id="runner" class="org.apache.commons.dbutils.QueryRunner" scope="prototype">
        <!--注入数据源-->
        <constructor-arg name="ds" ref="dataSource"></constructor-arg>
    </bean>

    <!-- 配置数据源 -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <!--连接数据库的必备信息-->
        <property name="driverClass" value="com.MysqL.jdbc.Driver"></property>
        <property name="jdbcUrl" value="jdbc:MysqL://localhost:3306/eesy"></property>
        <property name="user" value="root"></property>
        <property name="password" value="1234"></property>
    </bean>
</beans>

5.4 common notes

5.4. 1 for creating objects

Equivalent to: < bean id = "" class = "" >

5.4. 1.1 @Component

Function: let spring manage the resources. This is equivalent to configuring a bean in XML.

Attribute: Value: Specifies the ID of the bean. If the value attribute is not specified, the ID of the default bean is the class name of the current class. Initial lowercase.

5.4. 1.2 @Controller @Service @Repository

Their three annotations as like as two peas for @Component, are all identical.

They just provide more explicit semantics.

Details: if there is only one attribute to be assigned in the annotation and the name is value, value can not be written in the assignment.

5.4. 2 for injecting data

Equivalent to: < property name = "" ref = "" > < property name = "" value = "" >

5.4. 2.1 @Autowired

effect:

Automatically inject by type. When using annotation to inject attributes, the set method can be omitted. It can only inject other bean types. When there are multiple types matching, use the name of the object variable to be injected as the bean ID and look it up in the spring container. If it is found, the injection can also be successful. If you can't find it, report an error.

5.4. 2.2 @Qualifier

effect:

On the basis of automatic injection by type, it is injected according to the ID of the bean. It cannot be used independently when injecting fields, but must be used together with @ autowire; However, it can be used independently when injecting method parameters.

Properties:

Value: Specifies the ID of the bean.

5.4. 2.3 @Resource

effect:

Inject directly according to the ID of the bean. It can only inject other bean types.

Properties:

Name: Specifies the ID of the bean.

5.4. 2.4 @Value

effect:

Inject data of basic data type and string type

Properties:

Value: used to specify a value

5.4. 3 for changing the scope of action

Equivalent to: < bean id = "" class = "" scope = "" / >

5.4. 3.1 @Scope

effect:

Specifies the scope of the bean.

Properties:

Value: the value of the specified range

Value: Singleton prototype request session global session

5.4. 4 life cycle related (understand)

Equivalent to: < bean id = "" class = "" init method = "" destroy method = "" / >

5.4. 4.1 @postconstruct

Function: used to specify the initialization method.

5.4. 4.2 @PreDestroy

Role: used to specify the destruction method.

5.4. 5 selection of spring annotations and XML

5.5 spring management object details

In annotation as like as two peas in spring IoC configuration, the bean object is exactly the same as the XML configuration.

5.6 spring annotation only configuration

Here, the annotation based IOC configuration has been completed, but we still need the spring XML configuration file. Can we not write this bean XML, all configurations are implemented with annotations?

5.6. 1. Problems to be reconstructed

We found that we can't do without XML configuration files because we have a key configuration:

<!-- 告知spring在创建容器时要扫描注解的包 -->
<context:component-scan base-package="com.itheima"></context:component-scan>

If it can also be configured with annotations, we are a step away from XML files.

In addition, the configuration of data source and queryrunner also needs to be realized by annotation.

    <!--配置QueryRunner-->
    <bean id="runner" class="org.apache.commons.dbutils.QueryRunner" scope="prototype">
        <!--注入数据源-->
        <constructor-arg name="ds" ref="dataSource"></constructor-arg>
    </bean>

    <!-- 配置数据源 -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <!--连接数据库的必备信息-->
        <property name="driverClass" value="com.MysqL.jdbc.Driver"></property>
        <property name="jdbcUrl" value="jdbc:MysqL://localhost:3306/eesy"></property>
        <property name="user" value="root"></property>
        <property name="password" value="1234"></property>
    </bean>

5.6. 2 new notes

5.6. 2.1 @Configuration

effect:

Used to specify that the current class is a spring configuration class from which annotations will be loaded when creating a container. Annotationapplicationcontext (class with @ configuration annotation) is required to obtain the container.

Properties:

Value: used to specify the bytecode of the configuration class

Example code:

//spring的配置类,相当于bean.xml文件
@Configuration
public class SpringConfiguration {

}

be careful:

We have replaced the configuration file with class, but how to configure the package to be scanned when creating the container? Please look at the next note.

5.6. 2.2 @ComponentScan

effect:

Used to specify the packages that spring will scan when initializing the container. The function is the same as that in the spring XML configuration file: < context: component scan base package = "com. Itheima" /.

Properties:

Base packages: used to specify packages to scan. The same as the value attribute in this annotation.

Example code:

//spring的配置类,相当于bean.xml文件
@Configuration
@ComponentScan("com.itheima")
public class SpringConfiguration {

}

be careful:

We have configured the package to be scanned, but how to remove the data source and jdbctemplate object from the configuration file? Please look at the next note.

5.6. 2.3 @Bean

effect:

This annotation can only be written on the method and is used to store the return value of the current method as a bean object in the IOC container of spring.

Properties:

Name: specify a name (i.e. bean ID) for the object created by the current @ bean annotation method. When not written, the default value is the name of the current method.

Details:

When we configure a method with annotations, if the method has parameters, the spring framework will look for available bean objects in the container. The search method is the same as that of the Autowired annotation.

Example code:

public class JdbcConfig {

    /**
     * 用于创建一个QueryRunner对象
     * @param dataSource
     * @return
     */
    @Bean(name="runner")
    @Scope("prototype")
    public QueryRunner createQueryRunner(@Qualifier("ds2") DataSource dataSource){
        return new QueryRunner(dataSource);
    }

    /**
     * 创建数据源对象
     * @return
     */

    @Bean(name="ds1")
    public DataSource createDataSource1(){
        try {
            ComboPooledDataSource ds = new ComboPooledDataSource();
            ds.setDriverClass(driver);
            ds.setJdbcUrl("jdbc:MysqL://localhost:3306/eesy02");
            ds.setUser(username);
            ds.setPassword(password);
            return ds;
        }catch (Exception e){
            throw new RuntimeException(e);
        }
    }
}

be careful:

We have removed the data source and dbassit from the configuration file, and we can delete the bean XML. However, because there is no configuration file, the configuration of creating data source is written in the class. How to configure them? Please look at the next note.

5.6. 2.4 @PropertySource

effect:

For loading The configuration in the properties file. For example, when we configure the data source, we can write the information of connecting to the database into the properties configuration file, and we can use this annotation to specify the location of the properties configuration file.

Properties:

Value []: used to specify the location of the properties file. If it is under the classpath, you need to write classpath:

Example code:

public class JdbcConfig {

    @Value("${jdbc.driver}")
    private String driver;

    @Value("${jdbc.url}")
    private String url;

    @Value("${jdbc.username}")
    private String username;

    @Value("${jdbc.password}")
    private String password;

    /**
     * 创建数据源对象
     * @return
     */
    @Bean(name="ds2")
    public DataSource createDataSource(){
        try {
            ComboPooledDataSource ds = new ComboPooledDataSource();
            ds.setDriverClass(driver);
            ds.setJdbcUrl(url);
            ds.setUser(username);
            ds.setPassword(password);
            return ds;
        }catch (Exception e){
            throw new RuntimeException(e);
        }
    }
}

jdbc.properties文件:
	jdbc.driver=com.MysqL.jdbc.Driver
	jdbc.url=jdbc:MysqL://localhost:3306/eesy
	jdbc.username=root
	jdbc.password=root

be careful:

At this point, we already have two configuration classes, but they are not related. How to build their relationship? Please look at the next note.

5.6. 2.5 @Import

effect:

It is used to import other configuration classes. When importing other configuration classes, you can no longer write @ configuration annotation. Of course, there's no problem writing it.

Properties:

Value []: used to specify the bytecode of other configuration classes.

Example code:

@ComponentScan("com.itheima")
@Import(JdbcConfig.class)
@PropertySource("classpath:jdbcConfig.properties")
public class SpringConfiguration {

}

be careful:

We have configured everything to be configured, but a new problem arises. Since there is no configuration file, how to obtain the container? Please look at the next section.

5.6. 2.6 obtaining containers by annotation

ApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfiguration.class);

Chapter 6 spring integration JUnit [Master]

6.1 problems and solutions in testing

6.1. 1 question

In the test class, each test method has the following two lines of code:

ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
IAccountService as = ac.getBean("accountService",AccountService.class);

The purpose of these two lines of code is to obtain the container. If it is not written, a null pointer exception will be prompted directly. So it can't be deleted easily.

6.1. 2 Analysis of Solutions

To solve the above problems, what we need is that the program can automatically help us create containers. Once the program can automatically create a spring container for us, we don't need to create it manually, and the problem is solved.

We all know the principle of JUnit unit testing, but obviously JUnit can't be implemented because it can't know whether we use the spring framework, let alone help us create a spring container. Fortunately, JUnit exposes us an annotation that allows us to replace its runner.

At this time, we need to rely on the spring framework because it provides a runner that can read the configuration file (or annotation) to create the container. We just need to tell it where the configuration file is.

6.2 configuration steps

6.2. Step 1: replace the original runner with @ runwith annotation

@RunWith(SpringJUnit4ClassRunner.class)
public class AccountServiceTest {

}

6.2. Step 2: use @ contextconfiguration to specify the location of the spring configuration file

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfiguration.class)
public class AccountServiceTest {

}

6.2. Step 3: use @ Autowired to inject data into the variables in the test class

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfiguration.class)
public class AccountServiceTest {

    @Autowired
    private AccountService as = null;
}

6.3 why not configure test classes into XML

It can certainly be used in XML.

So why not configure it into XML?

The reason is as follows:

First: when we configure a bean in XML and spring loads the configuration file to create a container, the object will be created.

Second: the test class is only used when we test functions. In the project, it does not participate in program logic and will not solve requirements problems. Therefore, it is created and not used. If it is stored in the container, it will cause a waste of resources.

Therefore, based on the above two points, we should not configure the test into an XML file.

Chapter 7 relevant concepts of AOP [understanding]

7.1 AOP overview

7.1. 1 what is AOP

AOP: its full name is aspect oriented programming, that is, aspect oriented programming.

In short, it is to extract the repeated code of our program, and when it needs to be executed, use the dynamic agent technology to enhance our existing methods without modifying the source code.

7.1. 2 role and advantages of AOP

effect:

Advantages:

7.1. 3 implementation of AOP

Using dynamic agent technology

7.2 specific application of AOP

7.2. 1. Problems in the case

In the crud case of account implementation in Chapter 4, there are problems. The problems are:

Transactions are automatically controlled. In other words, we used setautocommit (true) of the connection object

This method controls transactions. If we execute one SQL statement every time, there is no problem, but if the business method executes multiple SQL statements at a time, this method cannot realize the function.

Take a look at the following example: let's add one more method in the business layer.

业务层接口

void transfer(String sourceName,String targetName,Float money);

业务层实现类

@Override 
public void transfer(String sourceName,Float money) { 
	//根据名称查询两个账户信息 
	Account source = accountDao.findByName(sourceName); 
	Account target = accountDao.findByName(targetName); 
	//转出账户减钱,转入账户加钱 
	source.setMoney(source.getMoney()-money); 
	target.setMoney(target.getMoney()+money); 
	//更新两个账户 
	accountDao.update(source); 
	int i=1/0; //模拟转账异常 
	accountDao.update(target); 
} 

When we execute, the transfer fails due to abnormal execution. However, because each execution of the persistence layer method is an independent transaction, transaction control cannot be realized (inconsistent with transaction consistency). It will reduce the money in the first account, but not increase the money in the second account.

7.2. 2 problem solving

terms of settlement:

Add a transaction control class to let the business layer control the submission and rollback of transactions.

Code of transactionmanager class:

/**
 * 和事务管理相关的工具类,它包含了,开启事务,提交事务,回滚事务和释放连接
 */
public class TransactionManager {

    private ConnectionUtils connectionUtils;

    public void setConnectionUtils(ConnectionUtils connectionUtils) {
        this.connectionUtils = connectionUtils;
    }

    /**
     * 开启事务
     */
    public  void beginTransaction(){
        try {
            connectionUtils.getThreadConnection().setAutoCommit(false);
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    /**
     * 提交事务
     */
    public  void commit(){
        try {
            connectionUtils.getThreadConnection().commit();
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    /**
     * 回滚事务
     */
    public  void rollback(){
        try {
            connectionUtils.getThreadConnection().rollback();
        }catch (Exception e){
            e.printStackTrace();
        }
    }


    /**
     * 释放连接
     */
    public  void release(){
        try {
            connectionUtils.getThreadConnection().close();//还回连接池中
            connectionUtils.removeConnection();
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

Transform the business layer implementation class (spring IOC is not used here)

/**
 * 账户的业务层实现类
 *
 * 事务控制应该都是在业务层
 */
public class AccountServiceImpl_OLD implements AccountService{

    private AccountDao accountDao;
    private TransactionManager txManager;

    public void setTxManager(TransactionManager txManager) {
        this.txManager = txManager;
    }

    public void setAccountDao(IAccountDao accountDao) {
        this.accountDao = accountDao;
    }

    @Override
    public List<Account> findAllAccount() {
        try {
            //1.开启事务
            txManager.beginTransaction();
            //2.执行操作
            List<Account> accounts = accountDao.findAllAccount();
            //3.提交事务
            txManager.commit();
            //4.返回结果
            return accounts;
        }catch (Exception e){
            //5.回滚操作
            txManager.rollback();
            throw new RuntimeException(e);
        }finally {
            //6.释放连接
            txManager.release();
        }
    }
	//其他方法此处省略,添加事务控制方法相同。
}

7.2. 3 new problems

The code in the previous section can realize transaction control through the transformation of the business layer. However, due to the addition of transaction control, a new problem also arises:

The business layer approach has become bloated and filled with a lot of duplicate code. And the business layer method and transaction control method are coupled.

Imagine that if we commit, roll back and release any method name change in resources at this time, we need to modify the code of the business layer. Moreover, this is only a business layer implementation class, and there may be more than a dozen or even dozens of such business layer implementation classes in the actual project.

We can use dynamic agents to solve this problem

7.2. 4 dynamic agent

7.2. 4.1 characteristics of dynamic agent

Bytecode is created as you use it and loaded as you use it.

This is also the difference between it and static proxy. Because the static proxy is bytecode, it is created and loaded as soon as it comes up.

Decorator mode is an embodiment of static agent.

7.2. 4.2 there are two common methods of dynamic agent

7.2. 5 solve the problems in the case

/**
 * 用于创建Service的代理对象的工厂
 */
public class beanfactory {

    private IAccountService accountService;

    private TransactionManager txManager;

    public void setTxManager(TransactionManager txManager) {
        this.txManager = txManager;
    }


    public final void setAccountService(IAccountService accountService) {
        this.accountService = accountService;
    }

    /**
     * 获取Service代理对象
     * @return
     */
    public IAccountService getAccountService() {
        return (IAccountService)Proxy.newProxyInstance(accountService.getClass().getClassLoader(),accountService.getClass().getInterfaces(),new InvocationHandler() {
                    /**
                     * 添加事务的支持
                     *
                     * @param proxy
                     * @param method
                     * @param args
                     * @return
                     * @throws Throwable
                     */
                    @Override
                    public Object invoke(Object proxy,Method method,Object[] args) throws Throwable {

                        if("test".equals(method.getName())){
                            return method.invoke(accountService,args);
                        }

                        Object rtValue = null;
                        try {
                            //1.开启事务
                            txManager.beginTransaction();
                            //2.执行操作
                            rtValue = method.invoke(accountService,args);
                            //3.提交事务
                            txManager.commit();
                            //4.返回结果
                            return rtValue;
                        } catch (Exception e) {
                            //5.回滚操作
                            txManager.rollback();
                            throw new RuntimeException(e);
                        } finally {
                            //6.释放连接
                            txManager.release();
                        }
                    }
                });
    }
}

After our transformation, the duplicate code used by the business layer to control transactions can be deleted.

Chapter 8 AOP in spring [mastering]

8.1 details of AOP in spring

8.1. 1 Description

Learning the AOP of spring is to realize the functions of the previous chapter through configuration.

8.1. 2 AOP related terms

8.1. 3 things to be clear about learning AOP in spring

a. Development phase (what we do)

Write core business code (development main line)

Extract the common code and make it into a notice. (to be done at the end of the development stage)

In the configuration file, the relationship between the pointcut and the notification is declared, that is, the aspect.

b. Run phase (completed by spring framework)

The spring framework monitors the execution of pointcut methods. Once it is monitored that the pointcut method is running, the proxy mechanism is used to dynamically create the proxy object of the target object. According to the notification category, the corresponding function of the notification is woven into the corresponding position of the proxy object to complete the complete code logic operation.

8.1. 4. Selection of agents

In spring, the framework will decide which dynamic proxy method to adopt according to whether the target class implements the interface.

8.2 XML based AOP configuration

When learning AOP of spring, take a simple account case as an example. And apply spring's IOC together. This is only to show the configuration mode of AOP, and it does not interact with the database.

8.2. 1. Environmental construction

8.2. 1.1 step 1: POM Adding dependencies to XML

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.0.2.RELEASE</version>
    </dependency>

    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.8.7</version>
    </dependency>
</dependencies>

8.2. 1.2 step 2: create spring's configuration file bean XML and import constraints

Here are the constraints to import AOP

<?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>

8.2. 1.3 step 3: configure IOC of spring

<!-- 配置srping的Ioc,把service对象配置进来-->
<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl"></bean>

8.2. 1.4 step 4: create a notification class

/**
 * 用于记录日志的工具类,它里面提供了公共的代码
 */
public class Logger {

    /**
     * 前置通知
     */
    public  void beforePrintLog(){
        System.out.println("前置通知Logger类中的beforePrintLog方法开始记录日志了。。。");
    }

    /**
     * 后置通知
     */
    public  void afterReturningPrintLog(){
        System.out.println("后置通知Logger类中的afterReturningPrintLog方法开始记录日志了。。。");
    }
    /**
     * 异常通知
     */
    public  void afterThrowingPrintLog(){
        System.out.println("异常通知Logger类中的afterThrowingPrintLog方法开始记录日志了。。。");
    }

    /**
     * 最终通知
     */
    public  void afterPrintLog(){
        System.out.println("最终通知Logger类中的afterPrintLog方法开始记录日志了。。。");
    }

    /**
     * 环绕通知
     * 问题:
     *      当我们配置了环绕通知之后,切入点方法没有执行,而通知方法执行了。
     * 分析:
     *      通过对比动态代理中的环绕通知代码,发现动态代理的环绕通知有明确的切入点方法调用,而我们的代码中没有。
     * 解决:
     *      Spring框架为我们提供了一个接口:ProceedingJoinPoint。该接口有一个方法proceed(),此方法就相当于明确调用切入点方法。
     *      该接口可以作为环绕通知的方法参数,在程序执行时,spring框架会为我们提供该接口的实现类供我们使用。
     *
     * spring中的环绕通知:
     *      它是spring框架为我们提供的一种可以在代码中手动控制增强方法何时执行的方式。
     */
    public Object aroundPrintLog(ProceedingJoinPoint pjp){
        Object rtValue = null;
        try{
            Object[] args = pjp.getArgs();//得到方法执行所需的参数
            System.out.println("Logger类中的aroundPringLog方法开始记录日志了。。。前置");
            rtValue = pjp.proceed(args);//明确调用业务层方法(切入点方法)
            System.out.println("Logger类中的aroundPringLog方法开始记录日志了。。。后置");
            return rtValue;
        }catch (Throwable t){
            System.out.println("Logger类中的aroundPringLog方法开始记录日志了。。。异常");
            throw new RuntimeException(t);
        }finally {
            System.out.println("Logger类中的aroundPringLog方法开始记录日志了。。。最终");
        }
    }
}

8.2. 2 configuration steps

8.2. 2.1 step 1: configure the notification class with bean tag

<!-- 配置Logger类 -->
<bean id="logger" class="com.itheima.utils.Logger"></bean>

8.2. 2.2 step 2: declare AOP configuration using AOP: config

aop:config

Function: used to declare the configuration of starting AOP.

<aop:config>
	<!-- 配置的代码都写在此处 -->
</aop:config>

8.2. 2.3 step 3: configure the aspect using AOP: aspect

aop:aspect

Function: used to configure section.

Properties:

8.2. 2.4 step 4: configure the pointcut expression using AOP: pointcut

aop:pointcut

Function: used to configure pointcut expressions, which specify which classes and methods to enhance.

Properties:

This tag is written inside the AOP: aspect tag and can only be used in the current aspect. It can also be written outside AOP: aspect, which becomes available for all aspects

<aop:pointcut id="pt1" expression="execution(* com.itheima.service.impl.*.*(..))"></aop:pointcut>

8.2. 2.5 step 5: configure the corresponding notification type using AOP: XXX

aop:before

Function: used to configure pre notification and specify that the enhanced method is executed before the pointcut method.

Properties:

Execution time point: executed before the pointcut method is executed

<aop:before method="beforePrintLog" pointcut-ref="pt1" ></aop:before>

aop:after-returning

Function: used to configure post notification

Properties:

Execution time point: the pointcut method is executed after normal execution. It and exception notification can only have one execution.

<aop:after-returning method="afterReturningPrintLog" pointcut-ref="pt1"></aop:after-returning>

aop:after-throwing

Function: used to configure exception notification

Properties:

Execution time point: the pointcut method is executed after an exception occurs. It and post notification can only execute one.

<aop:after-throwing method="afterThrowingPrintLog" pointcut-ref="pt1"></aop:after-throwing>

aop:after

Role: used to configure the final notification

Properties:

Execution time:

The pointcut method executes after it whether there is an exception or not.

aop:after method="afterPrintLog" pointcut-ref="pt1"></aop:after>

8.2. 3. Description of pointcut expression

Execution: execution of matching method (common)

Execution (expression)

Expression syntax: execution ([modifier] return value type package name. Class name. Method name (parameter))

Description:

Note:

Usually, we enhance the methods of the business layer, so the pointcut expressions are cut to the implementation classes of the business layer.

execution(* com.itheima.service.impl.*.*(..))

8.2. 4 surround notification

<aop:around method="aroundPrintLog" pointcut-ref="pt1"></aop:around>

aop:around :

Function: used to configure surround notifications

Properties:

explain:

It is a way for us to manually control when the enhanced code is executed in the code provided by the spring framework.

be careful:

In general, surround notifications are used independently

8.3 annotation based AOP configuration

8.3. 1. Environmental construction

8.3. 1.1 step 1: prepare necessary codes and configure POM xml

It is conducive to the code and POM in XML based AOP configuration XML is enough

8.3. 1.2 step 2: import the namespace of context 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"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       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
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

</beans>

8.3. 1.3 step 3: configure the resource usage annotation

/**
 * 账户的业务层实现类
 */
@Service("accountService")
public class AccountServiceImpl implements IAccountService{

}

8.3. 1.4 step 4: specify the package to be scanned by spring in the configuration file

<!-- 配置spring创建容器时要扫描的包-->
<context:component-scan base-package="com.itheima"></context:component-scan>

8.3. 2 configuration steps

8.3. 2.1 step 1: configure the notification class with annotations

@Component("logger")
public class Logger {

}

8.3. 2.2 step 2: use the @ aspect annotation on the notification class to declare as aspect

effect:

Declare the current class as a faceted class.

@Component("logger")
@Aspect//表示当前类是一个切面类
public class Logger {

}

8.3. 2.3 step 3: use annotation configuration notification on the enhanced method

@Before

Function: treat the current method as a pre notification.

Attribute: Value: used to specify the pointcut expression. You can also specify the reference of the pointcut expression.

/**
 * 前置通知
 */
@Before("execution(* com.itheima.service.impl.*.*(..))")
public  void beforePrintLog(){
    System.out.println("前置通知Logger类中的beforePrintLog方法开始记录日志了。。。");
}

@AfterReturning

Function: treat the current method as a post notification.

Attribute: Value: used to specify the pointcut expression. You can also specify the reference of the pointcut expression.

/**
 * 后置通知
 */
@AfterReturning("execution(* com.itheima.service.impl.*.*(..))")
public  void afterReturningPrintLog(){
    System.out.println("后置通知Logger类中的afterReturningPrintLog方法开始记录日志了。。。");
}

@AfterThrowing

Function: treat the current method as an exception notification.

Attribute: Value: used to specify the pointcut expression. You can also specify the reference of the pointcut expression.

/**
 * 异常通知
 */
@AfterThrowing("execution(* com.itheima.service.impl.*.*(..))")
public  void afterThrowingPrintLog(){
    System.out.println("异常通知Logger类中的afterThrowingPrintLog方法开始记录日志了。。。");
}

@After

Function: regard the current method as the final notification.

Attribute: Value: used to specify the pointcut expression. You can also specify the reference of the pointcut expression.

/**
 * 最终通知
 */
@After("execution(* com.itheima.service.impl.*.*(..))")
public  void afterPrintLog(){
    System.out.println("最终通知Logger类中的afterPrintLog方法开始记录日志了。。。");
}

8.3. 2.4 step 4: enable spring's support for annotation AOP in the spring configuration file

<!-- 配置spring开启注解AOP的支持 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>

8.3. 3. Notification annotation configuration

@Around

Function: treat the current method as a surround notification.

Attribute: Value: used to specify the pointcut expression. You can also specify the reference of the pointcut expression.

@Around("execution(* com.itheima.service.impl.*.*(..))")
public Object aroundPringLog(ProceedingJoinPoint pjp){
    Object rtValue = null;
    try{
        Object[] args = pjp.getArgs();//得到方法执行所需的参数

        System.out.println("Logger类中的aroundPringLog方法开始记录日志了。。。前置");

        rtValue = pjp.proceed(args);//明确调用业务层方法(切入点方法)

        System.out.println("Logger类中的aroundPringLog方法开始记录日志了。。。后置");

        return rtValue;
    }catch (Throwable t){
        System.out.println("Logger类中的aroundPringLog方法开始记录日志了。。。异常");
        throw new RuntimeException(t);
    }finally {
        System.out.println("Logger类中的aroundPringLog方法开始记录日志了。。。最终");
    }
}

8.3. 4 pointcut expression annotation

@pointcut

Role: specify pointcut expressions

Attribute: Value: used to specify the content of the expression

@pointcut("execution(* com.itheima.service.impl.*.*(..))")
private void pt1() {}

Reference method:

Original notification note

@Around("execution(* com.itheima.service.impl.*.*(..))")

After setting pointcut, it has the same effect as above.

@Around("pt1()")//注意,千万别忘了写括号

8.3. 5 configuration without XML

@Configuration
@ComponentScan(basePackages="com.itheima")
@EnableAspectJAutoProxy	//开启 spring 对注解 AOP 的支持
public class SpringConfiguration {
}

Chapter 9: jdbctemplate in spring

9.1 overview of jdbctemplate

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.

9.2 creation of jdbctemplate 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.

9.3 configuring data sources in spring

9.3. 1. Environmental construction

pom. Add the following dependencies to the XML

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.0.2.RELEASE</version>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>5.0.2.RELEASE</version>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-tx</artifactId>
        <version>5.0.2.RELEASE</version>
    </dependency>

    <dependency>
        <groupId>MysqL</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.6</version>
    </dependency>
</dependencies>

9.3. 2. Write 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
        http://www.springframework.org/schema/beans/spring-beans.xsd">
</beans>

9.3. 3 configuring data sources

C3p0 and DBCP can be used. Of course, the spring framework also provides a built-in data source. Here we use the built-in data source of spring.

<!-- 配置数据源-->
<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/eesy"></property>
    <property name="username" value="root"></property>
    <property name="password" value="root"></property>
</bean>

9.3. 4 configure the database connection information into the property file

[definition property file] jdbc.properties

jdbc.driverClass=com.MysqL.jdbc.Driver
jdbc.url=jdbc:MysqL://localhost:3306/eesy
jdbc.username=root
jdbc.password=root

[import external attribute file]

One way:

<!-- 引入外部属性文件: -->
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
	<property name="location" value="classpath:jdbc.properties"/>
</bean>

Another way:

<context:property-placeholder location="classpath:jdbc.properties"/>

9.4 add, delete, query and modify jdbctemplate

The database still uses the account table in eesy

9.4. 1 configure the jdbctemplate in the 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
        http://www.springframework.org/schema/beans/spring-beans.xsd">

	<!-- 配置一个数据库的操作模板:JdbcTemplate -->
	<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!-- 配置数据源-->
    <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/eesy"></property>
        <property name="username" value="root"></property>
        <property name="password" value="root"></property>
    </bean>
</beans>

9.4. 2. Basic addition, deletion, query and modification

public class JdbcTemplateDemo {
	public static void main(String[] args) {
		//1.获取spring容器
		ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
		//2.根据id获取bean对象
		JdbcTemplate jt = (JdbcTemplate) ac.getBean("jdbcTemplate");
		//3.执行操作
		//插入
		jt.exeute("insert into account(name,money)values('eee',500)");
		//保存
		jt.update("insert into account(name,"fff",5000);
		//修改
		jt.update("update account set money = money-? where id = ?",300,6)
		//删除
		jt.update("delete from account where id = ?",6);
		//查询所有
		List<Account> accounts = jt.query("select * from account where money > ? ",new AccountRowMapper(),500);
		for(Account o : accounts){
			System.out.println(o);
		}
		//使用 RowMapper 的方式查询一个(常用的方式)
		List<Account> as = jt.query("select * from account where id = ? ",55);
		System.out.println(as.isEmpty()?"没有结果":as.get(0));
		//使用 ResultSetExtractor 的方式查询一个(不常用的方式)
		Account account = jt.query("select * from account where id = ?",new AccountResultSetExtractor(),3);
		System.out.println(account);
		//查询返回一行一列:使用聚合函数,在不使用 group by 字句时,都是返回一行一列。最常用的就是分页中获取总记录条数
		Integer total = jt.queryForObject("select count(*) from account where money > ?",Integer.class,500);
 		System.out.println(total);
	}
}

/**
 * 定义Account的封装策略
 */
class AccountRowMapper implements RowMapper<Account>{
    /**
     * 把结果集中的数据封装到Account中,然后由spring把每个Account加到集合中
     * @param rs
     * @param rowNum
     * @return
     * @throws sqlException
     */
    @Override
    public Account mapRow(ResultSet rs,int rowNum) throws sqlException {
        Account account = new Account();
        account.setId(rs.getInt("id"));
        account.setName(rs.getString("name"));
        account.setMoney(rs.getFloat("money"));
        return account;
    }
}

9.5 using jdbctemplate in Dao

9.5. 1 prepare entity class

//账户的实体
public class Account implements Serializable {
	private Integer id;
	private String name;
	private Float money;
	//getter and setter 及 toString 此处省略..
}

9.5. 2. The first method: define the jdbctemplate in Dao

/**
 * 账户的持久层接口
 */
public interface IAccountDao {

    /**
     * 根据Id查询账户
     * @param accountId
     * @return
     */
    Account findAccountById(Integer accountId);

    /**
     * 根据名称查询账户
     * @param accountName
     * @return
     */
    Account findAccountByName(String accountName);

    /**
     * 更新账户
     * @param account
     */
    void updateAccount(Account account);
}

/**
 * 账户的持久层实现类
 * 此版本的 dao ,需要给 dao  注入 JdbcTemplate
 */
public class AccountDaoImpl2 implements IAccountDao {

    private JdbcTemplate jdbcTemplate;

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

    @Override
    public Account findAccountById(Integer accountId) {
        List<Account> accounts = jdbcTemplate.query("select * from account where id = ?",new BeanPropertyRowMapper<Account>(Account.class),accountId);
        return accounts.isEmpty()?null:accounts.get(0);
    }

    @Override
    public Account findAccountByName(String accountName) {
        List<Account> accounts = jdbcTemplate.query("select * from account where name = ?",accountName);
        if(accounts.isEmpty()){
            return null;
        }
        if(accounts.size()>1){
            throw new RuntimeException("结果集不唯一");
        }
        return accounts.get(0);
    }

    @Override
    public void updateAccount(Account account) {
        jdbcTemplate.update("update account set name=?,account.getId());
    }
}

bean. xml

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

    <!-- 配置账户的持久层-->
    <bean id="accountDao" class="com.itheima.dao.impl.AccountDaoImpl">
		<!-- 注入jdbcTemplate -->
        <property name="jdbcTemplate" ref="jdbcTemplate"></property>
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!--配置JdbcTemplate
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    <!-- 配置数据源-->
    <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/eesy"></property>
        <property name="username" value="root"></property>
        <property name="password" value="1234"></property>
    </bean>
</beans>

There is a small problem with this approach. 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;
	}

Can you extract it? Please look at the next section.

9.5. 3. The second method: let Dao 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 static class JdbcDaoSupport extends DaoSupport {
	//定义对象
	private JdbcTemplate jdbcTemplate;
	//set方法注入数据源,判断是否注入了,注入了就创建JdbcTemplate
	public final void setDateSource(DataSource dataSource) {
		if(this.jdbcTemplate == null || dataSource != this.jdbcTemplate.getDataSource()){
			//如果提供了数据源就创建JdbcTemplate
			this.jdbcTemplate = createJdbcTemplate(dataSource);
			initTemplateConfig();
		}
	}
	//使用数据源创建JdbcTemplate
	protected JdbcTemplate createJdbcTemplate(DataSource dataSource) {
		return new JdbcTemplate(dataSource);
	}
	//当然我们也可以通过注入JdbcTemplate对象
	public final void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
		this.jdbcTemplate = jdbcTemplate;
		initTemplateConfig();
	}
	//使用getJdbcTemplate方法获取操作模板对象
	public final JdbcTemplate getJdbcTemplate() {
		return this.jdbcTemplate;
	}
}

/**
 * 账户的持久层实现类
 * 此版本dao,只需要给它的父类注入一个数据源
 */
public class AccountDaoImpl extends JdbcDaoSupport implements IAccountDao {

    @Override
    public Account findAccountById(Integer accountId) {
        List<Account> accounts = super.getJdbcTemplate().query("select * from account where id = ?",accountId);
		//super.getJdbcTemplate()方法是从父类上继承下来的,直接使用getJdbcTemplate()也一样。
        return accounts.isEmpty()?null:accounts.get(0);
    }

    @Override
    public Account findAccountByName(String accountName) {
        List<Account> accounts = super.getJdbcTemplate().query("select * from account where name = ?",accountName);
        if(accounts.isEmpty()){
            return null;
        }
        if(accounts.size()>1){
            throw new RuntimeException("结果集不唯一");
        }
        return accounts.get(0);
    }

    @Override
    public void updateAccount(Account account) {
        super.getJdbcTemplate().update("update account set name=?,account.getId());
    }
}

bean. xml

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

    <!-- 配置账户的持久层-->
    <bean id="accountDao" class="com.itheima.dao.impl.AccountDaoImpl">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!-- 配置数据源-->
    <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/eesy"></property>
        <property name="username" value="root"></property>
        <property name="password" value="root"></property>
    </bean>
</beans>

Differences between the two Daos:

Chapter 10 transaction control in spring

10.1 spring transaction control

First: Java EE system is developed hierarchically, and transaction processing is located in the business layer. Spring provides a transaction processing solution for hierarchically designing the business layer.

Second: the spring framework provides us with a set of transaction control interfaces. The details are introduced in the second section. This set of interfaces is in spring-tx-5.0 2.RELEASE. Jar.

Third: the transaction control of spring is based on AOP. It can be implemented by programming or configuration. The focus of our study is to use configuration.

10.2 introduction to transaction control API in spring

10.2. 1 PlatformTransactionManager

This interface is spring's transaction manager, which provides our common methods of operating transactions, as shown in the following figure:

We all use its implementation classes in development

Objects that really manage transactions

10.2. two TransactionDe@R_419_1292 @n

It is the definition information object of a transaction. There are the following methods:

10.2. 2.1 isolation level of transactions

10.2. 2.2 communication behavior of affairs

10.2. 2.3 timeout

The default value is - 1 and there is no timeout limit. If yes, set in seconds.

10.2. 2.4 is it a read-only transaction

It is recommended that the query be set to read-only.

10.2. 3 TransactionStatus

This interface provides the specific running status of transactions. The method is described in the following figure:

10.3 XML based declarative transaction control (configuration mode) [key]

10.3. 1. Environmental construction

10.3. 1.1 step 1: to POM Adding dependencies to XML

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.0.2.RELEASE</version>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>5.0.2.RELEASE</version>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-tx</artifactId>
        <version>5.0.2.RELEASE</version>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-test</artifactId>
        <version>5.0.2.RELEASE</version>
    </dependency>

    <dependency>
        <groupId>MysqL</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.6</version>
    </dependency>

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

    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
    </dependency>
</dependencies>

10.3. 1.2 step 2: create spring configuration file and import constraints

You need to import AOP and TX namespaces here

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

10.3. 1.3 step 3: prepare database tables and entity classes

Continue to use the account table and account entity class of eesy database used in the previous chapter.

10.3. 1.4 step 4: write business layer interface and implementation class

/**
 * 账户的业务层接口
 */
public interface IAccountService {
    /**
     * 根据id查询账户信息
     * @param accountId
     * @return
     */
    Account findAccountById(Integer accountId);

    /**
     * 转账
     * @param sourceName    转成账户名称
     * @param targetName    转入账户名称
     * @param money         转账金额
     */
    void transfer(String sourceName,Float money);
}

/**
 * 账户的业务层实现类
 *
 * 事务控制应该都是在业务层
 */
public class AccountServiceImpl implements IAccountService{

    private IAccountDao accountDao;

    public void setAccountDao(IAccountDao accountDao) {
        this.accountDao = accountDao;
    }

    @Override
    public Account findAccountById(Integer accountId) {
        return accountDao.findAccountById(accountId);

    }

    @Override
    public void transfer(String sourceName,Float money) {
        System.out.println("transfer....");
            //2.1根据名称查询转出账户
            Account source = accountDao.findAccountByName(sourceName);
            //2.2根据名称查询转入账户
            Account target = accountDao.findAccountByName(targetName);
            //2.3转出账户减钱
            source.setMoney(source.getMoney()-money);
            //2.4转入账户加钱
            target.setMoney(target.getMoney()+money);
            //2.5更新转出账户
            accountDao.updateAccount(source);
            int i=1/0;
            //2.6更新转入账户
            accountDao.updateAccount(target);
    }
}

10.3. 1.5 step 5: write Dao interface and implementation class

/**
 * 账户的持久层接口
 */
public interface IAccountDao {

    /**
     * 根据Id查询账户
     * @param accountId
     * @return
     */
    Account findAccountById(Integer accountId);

    /**
     * 根据名称查询账户
     * @param accountName
     * @return
     */
    Account findAccountByName(String accountName);

    /**
     * 更新账户
     * @param account
     */
    void updateAccount(Account account);
}

/**
 * 账户的持久层实现类
 * 此版本dao,只需要给它的父类注入一个数据源
 */
public class AccountDaoImpl extends JdbcDaoSupport implements IAccountDao {

    @Override
    public Account findAccountById(Integer accountId) {
        List<Account> accounts = super.getJdbcTemplate().query("select * from account where id = ?",accountId);
        return accounts.isEmpty()?null:accounts.get(0);
    }

    @Override
    public Account findAccountByName(String accountName) {
        List<Account> accounts = super.getJdbcTemplate().query("select * from account where name = ?",account.getId());
    }
}

There is no custom account encapsulation class rowmapper, but the beanpropertyrowmapper provided by spring is used to encapsulate the account.

10.3. 1.6 step 6: configure the business layer and persistence layer pair in the configuration file

<!-- 配置业务层-->
<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
    <property name="accountDao" ref="accountDao"></property>
</bean>

<!-- 配置账户的持久层-->
<bean id="accountDao" class="com.itheima.dao.impl.AccountDaoImpl">
    <property name="dataSource" ref="dataSource"></property>
</bean>


<!-- 配置数据源-->
<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/eesy"></property>
    <property name="username" value="root"></property>
    <property name="password" value="root></property>
</bean>

10.3. 2 configuration steps

spring中基于XML的声明式事务控制配置步骤
    1、配置事务管理器
    2、配置事务的通知
            此时我们需要导入事务的约束 tx名称空间和约束,同时也需要aop的
            使用tx:advice标签配置事务通知
                属性:
                    id:给事务通知起一个唯一标识
                    transaction-manager:给事务通知提供一个事务管理器引用
    3、配置AOP中的通用切入点表达式
    4、建立事务通知和切入点表达式的对应关系
    5、配置事务的属性
           是在事务的通知tx:advice标签的内部

10.3. 2.1 step 1: configure the transaction manager

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
	<!-- 注入DataSource -->
    <property name="dataSource" ref="dataSource"></property>
</bean>

10.3. 2.2 step 2: configure the transaction notification to reference the transaction manager

<!-- 配置事务的通知-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
</tx:advice>

10.3. 2.3 step 3: configure transaction attributes

    <!-- 配置事务的属性
            isolation:用于指定事务的隔离级别。默认值是DEFAULT,表示使用数据库的默认隔离级别。
            propagation:用于指定事务的传播行为。默认值是required,表示一定会有事务,增删改的选择。查询方法可以选择SUPPORTS。
            read-only:用于指定事务是否只读。只有查询方法才能设置为true。默认值是false,表示读写。
            timeout:用于指定事务的超时时间,默认值是-1,表示永不超时。如果指定了数值,以秒为单位。
            rollback-for:用于指定一个异常,当产生该异常时,事务回滚,产生其他异常时,事务不回滚。没有默认值。表示任何异常都回滚。
            no-rollback-for:用于指定一个异常,当产生该异常时,事务不回滚,产生其他异常时事务回滚。没有默认值。表示任何异常都回滚。
    -->
    <tx:attributes>
        <tx:method name="*" propagation="required" read-only="false"/>
        <tx:method name="find*" propagation="SUPPORTS" read-only="true"></tx:method>
    </tx:attributes>

10.3. 2.4 step 4: configure AOP pointcut expression

<!-- 配置aop-->
<aop:config>
    <!-- 配置切入点表达式-->
    <aop:pointcut id="pt1" expression="execution(* com.itheima.service.impl.*.*(..))"></aop:pointcut>
</aop:config>

10.3. 2.5 step 5: configure the corresponding relationship between pointcut expression and transaction notification

<!-- 在 在 aop:config  标签内部:建立事务的通知和切入点表达式的关系 -->	
<aop:advisor advice-ref="txAdvice" pointcut-ref="pt1"></aop:advisor>

10.4 annotation based configuration

10.4. 1. Environmental construction

10.4. 1.1 step 1: configure POM xml

Same as XML based configuration, omitted

10.4. 1.2 step 2: create spring configuration files, import constraints, and configure scanned packages

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

    <!-- 配置spring创建容器时要扫描的包-->
    <context:component-scan base-package="com.itheima"></context:component-scan>

    <!-- 配置JdbcTemplate-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!-- 配置spring提供的内置数据源-->
    <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/eesy"></property>
        <property name="username" value="root"></property>
        <property name="password" value="root"></property>
    </bean>
</beans>

10.4. 1.3 step 3: create database tables and entity classes

The configuration is the same as that based on XML

10.4. 1.4 step 4: create business layer interfaces and implementation classes, and use annotations to let spring manage

/**
 * 账户的业务层实现类
 *
 * 事务控制应该都是在业务层
 */
@Service("accountService")
public class AccountServiceImpl implements IAccountService{

    @Autowired
    private IAccountDao accountDao;
	//其余代码和基于XML的配置相同
}

10.4. 1.5 step 5: create Dao interface and implementation class and use annotations to let spring manage

/**
 * 账户的持久层实现类
 */
@Repository("accountDao")
public class AccountDaoImpl implements IAccountDao {

    @Autowired
    private JdbcTemplate jdbcTemplate;
	//其余代码和基于XML的配置相同
}

10.4. 2 configuration steps

10.4. 2.1 step 1: configure the transaction manager and inject the data source

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"></property>
</bean>

10.4. 2.2 step 2: use @ transactional annotation in the business layer

@Service("accountService")
@Transactional(propagation= Propagation.SUPPORTS,readOnly=true)//只读型事务的配置
public class AccountServiceImpl implements IAccountService{

    @Autowired
    private IAccountDao accountDao;

    @Override
    public Account findAccountById(Integer accountId) {
        return accountDao.findAccountById(accountId);

    }

    //需要的是读写型事务配置
    @Transactional(propagation= Propagation.required,readOnly=false)
    @Override
    public void transfer(String sourceName,Float money) {
        System.out.println("transfer....");
            //2.1根据名称查询转出账户
            Account source = accountDao.findAccountByName(sourceName);
            //2.2根据名称查询转入账户
            Account target = accountDao.findAccountByName(targetName);
            //2.3转出账户减钱
            source.setMoney(source.getMoney()-money);
            //2.4转入账户加钱
            target.setMoney(target.getMoney()+money);
            //2.5更新转出账户
            accountDao.updateAccount(source);
            int i=1/0;
            //2.6更新转入账户
            accountDao.updateAccount(target);
    }
}

The attribute of this annotation has the same meaning as the attribute in XML. This annotation can appear on interfaces, classes and methods.

It appears on the interface, indicating that all implementation classes of the interface have transaction support.

It appears on the class, indicating that all methods in the class have transaction support

Appears on the method, indicating that the method has transaction support.

Priority of the above three positions: method > class > interface

10.4. 2.3 step 3: enable spring's support for annotation transactions in the configuration file

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

10.4. 3. Configuration without XML

/**
 * spring的配置类,相当于bean.xml
 */
@Configuration
@ComponentScan("com.itheima")
@Import({JdbcConfig.class,TransactionConfig.class})
@PropertySource("jdbcConfig.properties")
@EnableTransactionManagement
public class SpringConfiguration {
}

Chapter 11 @ r_ 419_ What's new with 1361 @ [learn]

11.1 JDK related upgrades

11.1. 1. JDK version requirements

@R_ 419_ 1361@.0 Its GA (general) version was released in September 2017. This version is written based on jdk8, so the versions below jdk8 will not be used. At the same time, it can be compatible with jdk9.

Tomcat version requires 8.5 and above.

11.1. 2 content updated with jdk8 version

11.2 update of core container

Spring framework 5.0 now supports candidate component indexes as an alternative to classpath scanning. This feature has been added to the classpath scanner to simplify the steps of adding candidate component IDs.

The application build task can define its own meta - inf / spring Components file. At compile time, the source model is self-contained, and JPA entities and spring components are marked.

Reading entities from the index rather than scanning class paths is no significant difference for small projects with less than 200 classes. However, it has a great impact on large projects. The cost of loading component indexes is lower. Therefore, as the number of classes increases, the start time of index reading will remain unchanged.

The cost of loading component indexes is cheap. Therefore, when the number of classes continues to grow, and the start-up time for index building can still maintain a constant, but for component scanning, the start-up time will increase significantly.

What this means for our developers on large spring projects is that the application startup time will be greatly reduced. Although 20 or 30 seconds seems like nothing, if you have to board hundreds of times a day, it's enough for you. Using component index can help you live more efficiently every day.

You can learn more about component indexing on spring's JIRA.

11.3 JetBrains kotlin language support

Kolin overview: it is an object-oriented language that supports functional programming style. Kotlin runs on the JVM, but the running environment is not limited to the JVM.

11.4 responsive programming style

An exciting feature of this spring release is the new responsive stack web framework. This stack is completely responsive and non blocking, suitable for event loop style processing, and can be extended with a small number of threads.

Reactive streams are from Netflix, pivot, typesafe, red hat, Oracle, twitter and spray An API specially developed by IO engineers. It provides a public API for the implementation of responsive programming to implement hibernate JPA. Here JPA is the API, and Hibernate is the implementation.

The reactive streams API is part of the official version of Java 9. In Java 8, you will need to specifically introduce dependencies to use the reactive streams API.

The support of spring framework 5.0 for streaming processing depends on project reactor, which specifically implements the reactive streams API.

Spring framework 5.0 has a new spring weblux module that supports responsive HTTP and websocket clients. Spring framework 5.0 also provides support for responsive web applications running on the server, including rest, HTML and websocket style interaction.

Spring weblux contains two independent server programming models:

Annotation based: used @ controller and other annotations of spring MVC;

Functional style routing and processing using java 8 lambda expressions.

With spring Webflux, you can now create a webclient, which is responsive and non blocking and can be used as an alternative to resttemplate.

Here is a webclient implementation using the rest endpoint of spring 5.0:

WebClient webClient = WebClient.create();
Mono person = webClient.get().uri("http://localhost:8080/movie/42").accept(MediaType.APPLICATION_JSON).exchange().then(response -> response.bodyToMono(Movie.class));

11.5 junit5 support

JUnit 5 Jupiter is fully supported, so you can use JUnit 5 to write tests and extensions. In addition, it also provides a programming and extension model. The Jupiter subproject provides a test engine to run Jupiter based tests on spring.

In addition, spring framework 5 also provides an extension for parallel testing in the spring testcontext framework.

For the responsive programming model, spring test also introduces the support of webtestclient integration test supporting spring Webflux, which is similar to mockmvc and does not need a running server. Using a simulated request or response, the WebTest client can be directly bound to the Webflux server-side facility.

You can find a complete list of enhancements brought about by this exciting testcontext framework here.

Of course, spring framework 5.0 still supports our old friend JUnit! At the time of writing this article, JUnit 5 was only developed to GA version. For JUnit 4, the spring framework will be supported for some time in the future.

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>