一、概念
Spring是一个开源的javaEE框架,为了解决企业级应用开发的复杂性。
它的根本目标只有一个:简化Java开发。
Spring的核心特性是控制反转(IOC)和面向切面编程(AOP)
依赖注入:传统做法中每个类需要管理自己依赖的对象,这导致了耦合高和测试难。而在Spring中,容器负责管理所有的bean,类只需要声明本身需要哪些依赖,Spring容器会将其所需的依赖注入其中,无需类自身管理这些依赖类。
面向接口编程:像日志、事务管理和安全这样会跨越系统多个组件的系统服务通常被称为横切关注点。AOP是使这些关注点分离的一项技术,并使这些服务模块化并以声明的方式将它们应用到受影响的组件中。
Spring特点:
- 方便解耦、简化开发
- Aop编程支持
- 方便程序测试
- 方便集合其他框架
- 方便进行事务操作
- 降低开发API难度
Spring 模块:
二、案例
1.下载SpringFramework
- https://spring.io/projects/spring-framework#overview
- https://github.com/spring-projects/spring-framework
- https://github.com/spring-projects/spring-framework/wiki/Spring-Framework-Artifacts
- https://repo.spring.io/webapp/#/artifacts/browse/tree/General/libs-milestone
- https://repo.spring.io/release/org/springframework/spring/
2.新建项目并导入包
3.编写Demo
<?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="wang" class="com.xiang.demo.User"></bean>
</beans>
public class User {
public void add(){
System.out.println("add...");
}
}
public class Test {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
User user = context.getBean("xiang", User.class);
System.out.println(user);
user.add();
}
}
三、IOC 控制反转
控制反转,把对象创建和对象之间的调用关系,交给Spring管理。
1.底层原理
xml解析、工厂模式、反射
A依赖B,并不会在A里直接创建B。而是通过工厂类获取B实例,工厂类生成B实例的方法则是解析xml文件并通过反射创建B的实例。
2.实现接口
IOC思想基于IOC容器完成,IOC容器底层就是对象工厂
IOC容器两种实现方式(两个接口):
- BeanFactory: IOC容器基本实现,Spring内部使用接口,不推荐开发人员使用。(加载配置文件时不创建对象,使用时才创建对象)
- ApplicationContext: BeanFactory 的子接口,提供更多的功能,供开发人员使用。(加载配置文件时不创建对象)
3.Bean管理
- Spring创建对象
- 2.Spring注入属性
Ⅰ.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="wang" class="com.xiang.demo.User"></bean>
</beans>
1.标签说明
<id>标签:声明对象bean的唯一标志
<class>标签:类的全路径
2.基于xml方式注入属性两种方式
1)使用set方式注入
2)使用有参构造函数注入
@Data
public class Book {
private String name;
private String author;
}
<?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">
<!--set属性注入-->
<bean id="book1" class="com.xiang.demo.Book">
<property name="name" value="java设计模式"/>
<property name="author" value="希昂"/>
</bean>
<!--有参构造-->
<bean id="book2" class="com.xiang.demo.Book">
<constructor-arg name="author" value="希昂"/>
<constructor-arg name="name" value="Linux"/>
</bean>
</beans>
3.p命名空间
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p ="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--p 命名空间-->
<bean id="bookP" class="com.xiang.demo.Book" p:author="希昂" p:name="算法导论" />
</beans>
Ⅱ.基于注解方式
1.概念:注解是代码特殊标记,作用于类上、方法上、属性上,简化xml配置。
2.常见配置Bean注解:
- @Component
- @Service
- @Controller
- @Repository
举个栗子
<?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">
<!--开启注解文件扫描 设置扫描包路径-->
<!--默认扫描配置-->
<context:component-scan base-package="com.wang"></context:component-scan>
<!--自定义扫描配置-->
<!--use-default-filters 设置为false时,过滤条件才生效-->
<context:component-scan base-package="com.wang" use-default-filters="false">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service"/>
</context:component-scan>
<context:component-scan base-package="com.wang" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/>
</context:component-scan>
</beans>
/**
* 不加value属性,默认id为类名
*/
@Component
public class BookService {
public void addBook(){
System.out.println("买本书看看");
}
}
@Test
public void testAnnotation(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans-context.xml");
BookService bookService = applicationContext.getBean("bookService", BookService.class);
System.out.println(bookService);
bookService.addBook();
}
4.属性注入注解
- @Autowired 根据属性类型注入
- @Qualifier 根据属性名称注入
- @Resource 可以根据类型或名称注入(默认类型、name属性根据名称注入)(javax注解,非Spring自带)
- @Value 注入普通类型
5.完全注解开发(替换上面component-scan 的xml)
@Configuration
@ComponentScan(basePackages = "com.wang")
public class Config {
}
@Test
public void testAnnotationConfig(){
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(Config.class);
BookService bookService = applicationContext.getBean("bookService", BookService.class);
System.out.println(bookService);
bookService.addBook();
}
四、AOP 面向切面编程
1.底层原理(动态代理)
有接口:JDK动态代理
//接口
public interface UserDao {
int add(int a, int b);
int subtract(int a, int b);
}
//实现类
public class UserDaoImpl implements UserDao {
@Override
public int add(int a, int b) {
System.out.println("a + b 执行了");
return a + b;
}
@Override
public int subtract(int a, int b) {
System.out.println("a - b 执行了");
return a - b;
}
}
//生成代理主方法
public class JdkProxyDemo {
public static void main(String[] args) {
UserDao userDao = new UserDaoImpl();
UserDao userDao2 = (UserDao) Proxy.newProxyInstance(JdkProxyDemo.class.getClassLoader(), new Class[]{UserDao.class}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("执行方法前...");
Object result = method.invoke(userDao, args);
System.out.println("执行方法后...");
return result;
}
});
int result = userDao2.add(1, 2);
System.out.println(result);
int result2 = userDao2.subtract(1, 2);
System.out.println(result2);
}
}
无接口:CGlib动态代理
2.术语
①.连接点: 类里面可以被增强/代理的方法,称为连接点。
②.切入点: 实际被增强/代理的方法,称为切入点。
③.通知: 对方法增加的功能等部分,称为通知。(前置通知、后置通知、环绕通知、异常通知、最终通知)
④.切面:把通知应用到切入点的过程(动作)。
3.AOP实操(准备)
Spring框架一般基于AspectJ实现AOP操作。
AspectJ不是Spring组成部分,是独立的AOP框架,一般将AspectJ和Spring 一起使用进行AOP操作。
基于AspectJ实现AOP的两种方式:
- xml配置文件
- 注解方式
4.切入表达式
描述对哪个类的哪个方法进行什么增强。
语法结构:execution( [权限修饰符] [返回类型] [类全路径] [方法名称] [参数列表] )
举例:
//1.对com.xiang.dao.UserDao的add增强
execution(* com.xiang.dao.UserDao.add(..))
//2.对com.xiang.dao.UserDao的所有方法增强
execution(* com.xiang.dao.UserDao.*(..))
//3.对com.xiang.dao.包里所有类的所有方法增强
execution(* com.xiang.dao.*.*(..))
5.实操
1.通知
//配置类
@Configuration
@ComponentScan(basePackages = "com.aop")
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class AopConfig {
}
//接口定义
public interface UserDao {
int add(int a, int b);
int subtract(int a, int b);
}
//接口实现
@Component
public class UserDaoImpl implements UserDao {
@Override
public int add(int a, int b) {
System.out.println("a + b 执行了");
return a + b;
}
@Override
public int subtract(int a, int b) {
System.out.println("a - b 执行了");
return a - b;
}
}
//切面定义
@Component
@Aspect
public class UserDaoProxy {
//前置通知
@Before(value = "execution(* com.aop.UserDaoImpl.*(..))")
public void before(){
System.out.println("前置通知...");
}
//在方法执行之后,无论方法是否正常完成(finally)
@After(value = "execution(* com.aop.UserDaoImpl.*(..))")
public void after(){
System.out.println("after...");
}
//在方法返回值之后
@AfterReturning(value = "execution(* com.aop.UserDaoImpl.*(..))")
public void afterReturning(){
System.out.println("afterReturning...");
}
//在方法返回抛出异常之后
@AfterThrowing(value = "execution(* com.aop.UserDaoImpl.*(..))")
public void afterThrowing(){
System.out.println("afterThrowing...");
}
//环绕通知
@Around(value = "execution(* com.aop.UserDaoImpl.*(..))")
public int around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("around之前...");
int i = (int) proceedingJoinPoint.proceed();
System.out.println("around之后...");
return i;
}
}
//Test
public class AopTest {
@Test
public void testAop1(){
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AopConfig.class);
UserDao userDao = applicationContext.getBean("userDaoImpl", UserDao.class);
userDao.add(1,2);
}
}
2.抽取切入点(Pointcut)
@Component
@Aspect
public class UserDaoProxy {
@Pointcut(value = "execution(* com.aop.UserDaoImpl.*(..))")
public void pointcut(){}
//前置通知
@Before(value = "pointcut()")
public void before(){
System.out.println("前置通知...");
}
//在方法执行之后,无论方法是否正常完成(finally)
@After(value = "pointcut()")
public void after(){
System.out.println("after...");
}
//在方法返回值之后
@AfterReturning(value = "pointcut()")
public void afterReturning(){
System.out.println("afterReturning...");
}
//在方法返回抛出异常之后
@AfterThrowing(value = "pointcut()")
public void afterThrowing(){
System.out.println("afterThrowing...");
}
//环绕通知
@Around(value = "pointcut()")
public int around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("around之前...");
int i = (int) proceedingJoinPoint.proceed();
System.out.println("around之后...");
return i;
}
}
3.多个通知
@Component
@Aspect
//设置切面优先级(数字越小越优先)
@Order(0)
public class UserDaoProxy2 {
@Pointcut(value = "execution(* com.aop.UserDaoImpl.*(..))")
public void pointcut(){}
//前置通知
@Before(value = "pointcut()")
public void before(){
System.out.println("UserDaoProxy2前置通知...");
}
}
4.xml配置切面
//被代理类
public class Book {
public void add(){
System.out.println("execute...");
}
}
//代理类
public class BookProxy {
public void before(){
System.out.println("before...");
}
public void after(){
System.out.println("after...");
}
}
//Test
public class AopTest {
@Test
public void testAop2(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans-aop-xml.xml");
Book book = applicationContext.getBean("book", Book.class);
book.add();
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context ="http://www.springframework.org/schema/context"
xmlns:aop ="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="book" class="com.aop.Book"></bean>
<bean id="bookProxy" class="com.aop.BookProxy"></bean>
<aop:config>
<aop:pointcut id="p" expression="execution(* com.aop.Book.*(..))"/>
<aop:aspect ref="bookProxy">
<aop:before method="before" pointcut-ref="p"/>
<aop:after method="after" pointcut-ref="p"/>
</aop:aspect>
</aop:config>
</beans>
五.JdbcTemplate
1.引入类
2.配置数据源
<?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 https://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.jdbcTemplate"></context:component-scan>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="url" value="jdbc:mysql:///db_user" />
<property name="username" value="root" />
<property name="password" value="123456" />
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource" />
</bean>
</beans>
3.配置JdbcTemplate
如上
4.操作数据库
1.实体类
@Data
public class Book {
private int id;
private String name;
private String author;
}
2.Dao层
public interface BookDao {
void add(Book book);
void update(Book book);
void delete(int id);
int count();
Book findById(int id);
List<Book> findAll();
void batchInsert(List<Book> books);
void batchUpdate(List<Book> books);
void batchDelete(List<Integer> bookIds);
}
@Repository
public class BookDaoImpl implements BookDao {
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
public void add(Book book) {
String insertSql = "insert into book values(?,?,?)";
Object[] args = {book.getId(), book.getName(), book.getAuthor()};
int num = jdbcTemplate.update(insertSql, args);
System.out.println(num);
}
@Override
public void update(Book book) {
String updateSql = "update book set name =? , author =? where id =?";
Object[] args = {book.getName(), book.getAuthor(), book.getId()};
int num = jdbcTemplate.update(updateSql, args);
System.out.println(num);
}
@Override
public void delete(int id) {
String deleteSql = "delete from book where id = ? ";
int num = jdbcTemplate.update(deleteSql, id);
System.out.println(num);
}
@Override
public int count() {
String countSql = "select count(*) from book";
int num = jdbcTemplate.queryForObject(countSql, Integer.TYPE);
return num;
}
@Override
public Book findById(int id) {
String findSql = "select * from book where id =? ";
Book book = jdbcTemplate.queryForObject(findSql, new BeanPropertyRowMapper<>(Book.class), id);
return book;
}
@Override
public List<Book> findAll() {
String findAllSql = "select * from book";
List<Book> books = jdbcTemplate.query(findAllSql, new BeanPropertyRowMapper<>(Book.class));
return books;
}
@Override
public void batchInsert(List<Book> books) {
String batchInsert = "insert into book values(?, ?, ?)";
List<Object[]> list = books.stream().map(book -> new Object[]{book.getId(), book.getName(), book.getAuthor()}).collect(Collectors.toList());
jdbcTemplate.batchUpdate(batchInsert, list);
}
@Override
public void batchUpdate(List<Book> books) {
String batchUpdate = "update book set name = ?, author = ? where id = ?";
List<Object[]> list = books.stream().map(book -> new Object[]{book.getName(), book.getAuthor(), book.getId()}).collect(Collectors.toList());
jdbcTemplate.batchUpdate(batchUpdate, list);
}
@Override
public void batchDelete(List<Integer> bookIds) {
String batchDelete = "delete from book where id = ?";
List<Object[]> list = bookIds.stream().map(id -> new Object[]{id}).collect(Collectors.toList());
jdbcTemplate.batchUpdate(batchDelete, list);
}
}
3.Service层
@Service
public class BookService {
@Autowired
private BookDao bookDao;
public void add(Book book){
bookDao.add(book);
}
public void update(Book book){
bookDao.update(book);
}
public void delete(int id){
bookDao.delete(id);
}
public int count(){
return bookDao.count();
}
public Book findById(int id){
return bookDao.findById(id);
}
public List<Book> findAll(){
return bookDao.findAll();
}
public void batchInsert(List<Book> books){
bookDao.batchInsert(books);
}
public void batchUpdate(List<Book> books){
bookDao.batchUpdate(books);
}
public void batchDelete(List<Integer> bookIds){
bookDao.batchDelete(bookIds);
}
}
4.Test
public class TestDemo {
@Test
public void add() {
ApplicationContext context = new ClassPathXmlApplicationContext("beans-jdbcTemplate.xml");
BookService bookService = context.getBean("bookService", BookService.class);
Book book = new Book(1,"Java","高斯林");
bookService.add(book);
}
@Test
public void update() {
ApplicationContext context = new ClassPathXmlApplicationContext("beans-jdbcTemplate.xml");
BookService bookService = context.getBean("bookService", BookService.class);
Book book = new Book(1,"Java","高斯林2");
bookService.update(book);
}
@Test
public void delete() {
ApplicationContext context = new ClassPathXmlApplicationContext("beans-jdbcTemplate.xml");
BookService bookService = context.getBean("bookService", BookService.class);
bookService.delete(1);
}
@Test
public void findById() {
ApplicationContext context = new ClassPathXmlApplicationContext("beans-jdbcTemplate.xml");
BookService bookService = context.getBean("bookService", BookService.class);
Book book = bookService.findById(2);
System.out.println(book);
}
@Test
public void countAll() {
ApplicationContext context = new ClassPathXmlApplicationContext("beans-jdbcTemplate.xml");
BookService bookService = context.getBean("bookService", BookService.class);
int num = bookService.count();
System.out.println(num);
}
@Test
public void findAll() {
ApplicationContext context = new ClassPathXmlApplicationContext("beans-jdbcTemplate.xml");
BookService bookService = context.getBean("bookService", BookService.class);
List<Book> list = bookService.findAll();
System.out.println(list);
}
@Test
public void batchInsert() {
ApplicationContext context = new ClassPathXmlApplicationContext("beans-jdbcTemplate.xml");
BookService bookService = context.getBean("bookService", BookService.class);
bookService.batchInsert(Arrays.asList(new Book(5,"Java5", "Author5"), new Book(6,"Java6", "Author6")));
}
@Test
public void batchUpdate() {
ApplicationContext context = new ClassPathXmlApplicationContext("beans-jdbcTemplate.xml");
BookService bookService = context.getBean("bookService", BookService.class);
bookService.batchUpdate(Arrays.asList(new Book(5,"Java5-5", "Author5-5"), new Book(6,"Java6-6", "Author6-6")));
}
@Test
public void batchDelete() {
ApplicationContext context = new ClassPathXmlApplicationContext("beans-jdbcTemplate.xml");
BookService bookService = context.getBean("bookService", BookService.class);
bookService.batchDelete(Arrays.asList(5,6));
}
}
六.Spring事务管理
事务是数据库操作基本单元,逻辑上一组动作,要么都成功,要么都失败。
1.事务特性(ACID)
- 原子性
- 一致性
- 隔离性
- 持久性
2.事务管理:
- 编程式事务
- 声明式事务 (原理AOP)
- xml配置方式
- 注解方式
3.实践
①xml配置文件方式
xml配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx https://www.springframework.org/schema/tx/spring-tx.xsd">
<context:component-scan base-package="com.transaction"></context:component-scan>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="url" value="jdbc:mysql:///db_user" />
<property name="username" value="root" />
<property name="password" value="123456" />
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource" />
</bean>
<!--配置transactionManager-->
<bean id = "transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<tx:advice id="transactionInterceptor">
</tx:advice>
<!--通过切点配置加事务的方法-->
<aop:config>
<aop:pointcut id="pt" expression="execution(* com.transaction.service.AccountService.*(..))"/>
<aop:advisor advice-ref="transactionInterceptor" pointcut-ref="pt"></aop:advisor>
</aop:config>
</beans>
Dao层
public interface AccountDao {
void addMoney(String userName, int account);
void reduceMoney(String userName, int account);
}
@Repository
public class AccountDaoImpl implements AccountDao{
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
public void addMoney(String userName, int account) {
String add = "update user_account set account = account + ? where user_name = ?";
jdbcTemplate.update(add, account, userName);
}
@Override
public void reduceMoney(String userName, int account) {
String reduce = "update user_account set account = account - ? where user_name = ?";
jdbcTemplate.update(reduce, account, userName);
}
}
Service层
@Service
public class AccountService {
@Autowired
private AccountDao accountDao;
public void transfer(){
accountDao.addMoney("wang", 100);
accountDao.reduceMoney("xiang", 100);
System.out.println("转账完毕");
}
}
Test层
public class TxTest {
@Test
public void test1(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans-transaction1.xml");
AccountService accountService = applicationContext.getBean("accountService", AccountService.class);
accountService.transfer();
}
}
②注解方式
xml配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
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/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx https://www.springframework.org/schema/tx/spring-tx.xsd">
<context:component-scan base-package="com.transaction"></context:component-scan>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="url" value="jdbc:mysql:///db_user" />
<property name="username" value="root" />
<property name="password" value="123456" />
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource" />
</bean>
<!--配置transactionManager-->
<bean id = "transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
</beans>
Dao层:同上,略
Service层:
@Service
@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.REPEATABLE_READ, readOnly = false, noRollbackFor = ArithmeticException.class)
public class AccountService {
@Autowired
private AccountDao accountDao;
public void transfer(){
accountDao.addMoney("wang", 100);
//int a = 10/0;
accountDao.reduceMoney("xiang", 100);
System.out.println("转账完毕");
}
}
Test:
public class TxTest {
@Test
public void test2(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans-transaction2.xml");
AccountService accountService = applicationContext.getBean("accountService", AccountService.class);
accountService.transfer();
}
}
③完全注解方式
1.配置类
@Configuration
@ComponentScan(basePackages = "com.transaction")
@EnableTransactionManagement
public class TxConfig {
@Bean
public DruidDataSource dataSource(){
DruidDataSource dataSource = new DruidDataSource();
dataSource.setUrl("jdbc:mysql:///db_user");
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUsername("root");
dataSource.setPassword("123456");
return dataSource;
}
@Bean
public JdbcTemplate jdbcTemplate(DataSource dataSource){
JdbcTemplate jdbcTemplate = new JdbcTemplate();
jdbcTemplate.setDataSource(dataSource);
return jdbcTemplate;
}
@Bean
public DataSourceTransactionManager dataSourceTransactionManager(DataSource dataSource){
DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
transactionManager.setDataSource(dataSource);
return transactionManager;
}
}
2.Dao层:同上(xml配置方式),略
3.Service层:同上(注解方式),略
4.Test
public class TxTest {
@Test
public void test3(){
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(TxConfig.class);
AccountService accountService = applicationContext.getBean("accountService", AccountService.class);
accountService.transfer();
}
}
4.Transactional参数
@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.REPEATABLE_READ)
- propagation:事务传播机制
- ioslation:事务隔离级别
- timeout:超时时间
- readOnly:是否只读
- rollbackFor: 哪些异常需要回滚
- noRollbackFor: 哪些异常不需要回滚
七、日志整合
1.添加jar包依赖
2.配置log4j2.xml
<?xml version="1.0" encoding="UTF-8"?>
<!--日志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL -->
<!--Configuration后面的status用于设置log4j2自身内部的信息输出,可以不设置,当设置成trace时,可以看到log4j2内部各种详细输出-->
<configuration status="INFO">
<!--先定义所有的appender-->
<appenders>
<!--输出日志信息到控制台-->
<console name="Console" target="SYSTEM_OUT">
<!--控制日志输出的格式-->
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
</console>
</appenders>
<!--然后定义logger,只有定义了logger并引入的appender,appender才会生效-->
<!--root:用于指定项目的根日志,如果没有单独指定Logger,则会使用root作为默认的日志输出-->
<loggers>
<root level="info">
<appender-ref ref="Console"/>
</root>
</loggers>
</configuration>
3.Test
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class LogMain {
private final static Logger log = LoggerFactory.getLogger(LogMain.class);
public static void main(String[] args) {
log.info("this is Main method");
}
}
八、JUnit
1.引入jar包
2.Test类
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:beans-transaction1.xml")
public class JUnit4Demo {
@Autowired
private AccountService accountService;
@Test
public void test(){
accountService.transfer();
}
}
九、Webflux
1.概念
Spring5 新加的模块,用于Web开发,使用响应式编程。
有异于SpringMvc基于Servlet容器,Webflux是一种异步非阻塞的框架,核心是基于Reactor的相关API.
异步与同步(针对调用方):调用方需被调用方返回结果才能执行其他事件为同步, 调用方无需等待结果就能执行其他事件为异步;
阻塞与非阻塞(针对被调用方): 被调用方收到请求后执行完成后返回响应为阻塞, 被调用方收到请求后立即响应为非阻塞;
Webflux特点:
- 异步非阻塞:提供系统吞吐量和伸缩性。
- 函数式编程:使用函数式编程实现路由请求
与SpringMvc异同:
- 都可以使用注解方式,都可以运行在tomcat容器中
- SpringMvc采用命令式编程,Webflux采用响应式编程;
2.响应式编程
1.响应式编程操作中,Reactor满足Reactive规范框架
2.Reactor两个核心类:Mono和Flux, 这两个类实现了接口Publisher,提供了丰富操作符。Flux对象时发布者,返回N个元素;Mono实现发布者,返回0或1个元素
3.Flux和Mono都是数据流的发布者,使用Flux和Mono都可以发出三种数据信号:元素值、错误信号、完成信号。错误信号和完成信号都代表终止信号,终止信号用于告诉订阅者数据流结束了,错误终止数据流同时把错误信息传递给订阅者。
十、附代码Demo地址
https://github.com/user0819/spring5_demo.git