前言
?ladies and gentleman?,?你们好 ,我是羡羡 , 这节我们来介绍 Spring JDBC 与 AOP
?
记得笑着学奥😊
目录
🙏Spring JDBC
🎃AOP(面向切面)
💍连接点:?
💼通知
🧢结语 :?
Spring JDBC
? ? ? ?
🧢
Spring 是个一站式框架:Spring 自身也提供了控制层的 SpringMVC和持久层的 Spring JdbcTemplate。
🙏首先我们需要在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就不再讲述过多
? ? ? 但是后面我们需要引入spring事务管理, 所以这里JdbcTemplate还是得了解
AOP(面向切面)
? ?
🎃
AOP 是 OOP 的延续,是软件开发中的一个热点,也是 Spring 框架中的一个重要内容。利用 AOP 可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率
这么说不好理解 , 我们先来看如果不使用AOP的方式写代码是怎样去写的
?
🎃这里为了示例, 请出我的好兄弟 : 李雷(虽然我不知道他是否愿意, 我猜他知道的话肯定是下面这个表情,hhhhhhhhh)
? ? ? ? 例如 : 李雷你一会下去吃饭把垃圾倒了, 或者不吃饭出去玩之前把垃圾倒了
?
那么从编程的思想来看, 这里有三个方法 :?
吃饭 , 倒垃圾 , 出去玩
这里我们看出 , 无论李雷是吃饭还是出去玩 , 那么他都应该倒垃圾
所以我们直接可以将倒垃圾这个功能提取出来, 把倒垃圾这个功能看成一个横切面
让功能切入到我们的业务代码中即可
不使用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):类中可以被增强的方法,这个方法就被称为连接点
? ? ? ?
? ? ?
无论李雷是否是吃饭还是出去玩, 我们都可以让它倒垃圾 , 那么此时吃饭和出去玩这两个方法就是连接点
?
💍
切入点(pointcut):类中有很多方法可以被增强,但实际中只有 add 和 update
被增了,那么 add 和 update 方法就被称为切入点(实际实现的连接点)
? ?
?李雷这时候选择了去吃饭, 那么此时去吃饭这个方法就是切入点
?
💍
通知(Advice): 通知是指一个切面在特定的连接点要做的事情(增强的功能)。通知分为方法执行前通知,方法执行后通知,环绕通知等
? ?
? ? ?
这里通知指的就是倒垃圾这件事, 我们让李雷吃饭前倒垃圾, 就是前置通知, 饭吃完倒垃圾就是后置通知
?
💍
切面(Aspect):把通知添加到切入点的过程叫切面
? ?
切面就是我们告诉李雷去吃饭的话记得倒垃圾这个过程
?
💍
目标(Target): 代理的目标对象(要增强的类)
? ?
目标是我们具体去增强方法所属的类(目标类)
?
💍
代理(Proxy): 向目标对象应用通知之后创建的代理对象
?
?我们仅仅配置了AOP ,那么方法执行时, 谁去执行切面(增强的功能)呢? 答案就是代理对象帮我们去调用的
?
注解实现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("李雷去吃饭");
}
}
这里我们看到标签中有这样一个表达式
?
execution(* com.ff.spring.dao.UserDao.methodEat(..))
? ? ?
🎃 可以看出 , 它配置的是我们要增强的方法(此处为methodEat()) , 前面 * 表示这个方法返回值 ,
method(..) 中 .. 表示这个方法里可能有多个参数 ,例如我们上面这个方法 返回值void,没有参数, 所以这里也可以将 * 换成 void , .. 可以直接去掉
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");
}
这里有个参数 throwing , "e" 就代表返回的异常对象,我们可以通过异常对象获得异常的信息
?
🎃异常通知就是出了异常的话才会通知 , 例如李雷还没倒垃圾 ,然后被辅导员碰巧查宿(出现了异常) ,?这时候就得指定异常通知去做什么事情
?
最终通知
@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一定要笑, 哎 ,笑着学, 嘿嘿
|