前言
ladies and gentleman , 你们好 ,我是羡羡 , 这节我们来介绍 Spring JDBC 与 AOP
记得笑着学奥😊
目录
Spring JDBC
🙏首先我们需要在maven导入Spring JDBC的 jar 依赖
<!-- spring-jdbc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.2.RELEASE</version>
</dependency>
但是spring并不直接参与数据库的连接 , 我们可以使用一些第三方的数据库组件
这里我们使用阿里的druid 数据源,导入jar
阿里 druid(德鲁伊) 数据库连接组件 自身还提供了数据库连接池技术 sql监控
<!-- 阿里数据源 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
druid 具有以下功能
数据库连接 封装了jdbc
数据库连接池 频繁的连接数据库 创建销毁连接对象 Connection SqlSession 开销较大
🎃 创建一个连接对象的池子 与数据库交互时,可以先从连接池中获取连接,用完后不进行销毁,只是还回到连接池
减少创建销毁的开销
让Spring管理创建Druid数据库连接对象
连接我们使用的是mysql数据库 , 所以jar 也是必不可少
创建db.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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://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">
<!--读入文件-->
<context:property-placeholder location="config.properties"/>
<!--配置数据源-->
<bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${driverName}"/>
<property name="url" value="${urlName}"/>
<property name="username" value="${uName}"/>
<property name="password" value="${pwd}"/>
<!--initialSize为初始化连接个数-->
<property name="initialSize" value="${initialSize}"/>
<!--maxActive为最大连接数-->
<property name="maxActive" value="${maxActive}"/>
</bean>
<!--spring提供JdbcTemplate封装类-->
<!--启动spring时创建jdbcTemplate类-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="druidDataSource"/>
</bean>
</beans>
driverName=com.mysql.cj.jdbc.Driver
urlName=jdbc:mysql://127.0.0.1:3306/mybatis_db?characterEncoding=utf8&useSSL=false&serverTimezone=UTC
uName=root
pwd=root
initialSize=5
maxActive=10
💍在 spring.xml 导入 db.xml 文件
<import resource="db.xml"/>
@Repository(value = "userDao")
public class UserDao {
//注入JdbcTemplate
@Autowired
JdbcTemplate jdbcTemplate;
public void saveUser(){
jdbcTemplate.update("insert into admin(account,password,sex) values (?,?,?)","li","111","男");
}
}
ApplicationContext app = new ClassPathXmlApplicationContext("spring.xml");
UserService userService=app.getBean("userService",UserService.class);
userService.save(); //调用执行
💼 JdbcTemplate里面提供的方法也可以支持我们对数据库的各种操作(查询等),在数据库连接方面 ,我们后面都会使用mybatis框架 , 所以JdbcTemplate就不再讲述过多
AOP(面向切面)
🎃 AOP 是 OOP 的延续,是软件开发中的一个热点,也是 Spring 框架中的一个重要内容。利用 AOP 可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率
这么说不好理解 , 我们先来看如果不使用AOP的方式写代码是怎样去写的
这里我们看出 , 无论李雷是吃饭还是出去玩 , 那么他都应该倒垃圾
所以我们直接可以将倒垃圾这个功能提取出来, 把倒垃圾这个功能看成一个横切面
让功能切入到我们的业务代码中即可
不使用AOP是这样来做的 :
public void method1(){
System.out.println("李雷吃饭");
method3();
}
public void method2(){
System.out.println("李雷出去玩");
method3();
}
public void method3(){
System.out.println("倒垃圾");
}
我们把倒垃圾抽取出去, 在 method1() 与 method2() 去调用这个方法
但为什么可以纯java实现 , 我们还要去使用AOP呢 ?
因为在平时的开发过程中 , 代码量比较大, 采用这样一直调用的方式 , method3直接侵入到其他的业务代码中, 这样很容易出现问题. 使用AOP的方式 , 它采用动态代理的方式来为我们的业务代码添加相应的逻辑 , 不需要我们去考虑这么多, 降低了耦合度,减少重复,专注业务
我们现在来正式介绍AOP的使用方式(这里采用注解方式)
对于AOP的实现,我们这里使用 AspectJ 这样一个框架, Spring对其进行了管理,AspectJ 是一个优秀面向切面的框架,它扩展了 Java 语言,提供了强大的切面实现。
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.2.2.RELEASE</version>
</dependency>
在maven导入AOP所需 jar
<aop:aspectj-autoproxy/>
在Spring.xml中 开启AspectJ 支持
连接点:
这里需要介绍几个专业词 :
💍 连接点(Joinpoint):类中可以被增强的方法,这个方法就被称为连接点
无论李雷是否是吃饭还是出去玩, 我们都可以让它倒垃圾 , 那么此时吃饭和出去玩这两个方法就是连接点
李雷这时候选择了去吃饭, 那么此时去吃饭这个方法就是切入点
💍 通知(Advice): 通知是指一个切面在特定的连接点要做的事情(增强的功能)。通知分为方法执行前通知,方法执行后通知,环绕通知等
这里通知指的就是倒垃圾这件事, 我们让李雷吃饭前倒垃圾, 就是前置通知, 饭吃完倒垃圾就是后置通知
💍 切面(Aspect):把通知添加到切入点的过程叫切面
切面就是我们告诉李雷去吃饭的话记得倒垃圾这个过程
💍 目标(Target): 代理的目标对象(要增强的类)
目标是我们具体去增强方法所属的类(目标类)
💍 代理(Proxy): 向目标对象应用通知之后创建的代理对象
我们仅仅配置了AOP ,那么方法执行时, 谁去执行切面(增强的功能)呢? 答案就是代理对象帮我们去调用的
@Component
@Aspect
public class AopDemo {
@Before("execution(* com.ff.spring.dao.UserDao.methodEat(..))")
public void method(){
System.out.println("倒垃圾");
}
}
@Component 这个注解标签是将这个类交给Spring管理
@Aspect 说明这个类里的方法将被配置为切面
@Before() 代表前置通知
@Repository(value = "userDao")
public class UserDao {
//将被增强的方法
public void methodEat(){
System.out.println("李雷去吃饭");
}
}
ApplicationContext app = new ClassPathXmlApplicationContext("spring.xml");
UserDao userDao=app.getBean("userDao",UserDao.class);
userDao.methodEat();
测试 :
可以看到, 前置通知生效
🎃这里我们载介绍一下后置通知, 异常通知, 环绕通知, 最终通知
@After ( "execution(* com.ff.spring.demo1.dao.UserDao.*(..))" ) 后置通知注解
通知
异常通知
@AfterThrowing(value = "execution(* com.ff.spring.demo1.dao.UserDao.*(..))",
throwing = "e")
public void afterthrow(Throwable){
System.out.println("afterthrow");
}
@AfterReturning("execution(* com.ff.spring.demo1.dao.UserDao.*(..))")
public void afterreturn(){
System.out.println("afterreturn");
}
最终通知是在方法return后执行的通知
环绕通知
@Around("execution(* com.ff.spring.dao.UserDao.methodEat1(..))")
public void around(ProceedingJoinPoint point){
System.out.println("倒垃圾");
try {
point.proceed();
} catch (Throwable throwable) {
throwable.printStackTrace();
System.out.println("快倒垃圾");
}
System.out.println("倒垃圾");
}
通过代码就可以看出 , 环绕通知其实可以代替以上通知 , 你可以在环绕通知中单独使用前置,后置,或者异常通知 , 环绕通知也是一个综合通知
结果 :
这里相当于我们在环绕通知中使用了前置和后置 , 但是这里没有出现异常,所以异常通知不会执行
结语 :
这节我们介绍了SpringJDBC 与 AOP , 后面我们将会引入Spring事务管理这样一个模块, 所以这
两个要先介绍 ,最后感谢阅读😊
学spring一定要笑, 哎 ,笑着学, 嘿嘿