Spring框架:第七章:AOP切面编程,java面试数据库调优

// 调用目标对象方法

result = method.invoke(target, args);

} finally {

// 后置通知

LogUtils.logAfter(method.getName(), args);

}

// 返回通知

LogUtils.logAfterReturning(method.getName(), result);

} catch (Exception e) {

// 异常通知

LogUtils.logAfterThrowing(method.getName(), e);

}

return result;

}

});

}

public static void main(String[] args) {

Calculate calculate = new Calculator();

Calculate proxy = (Calculate) createProxy(calculate);

System.out.println(proxy.add(100, 200));

System.out.println(“===============================”);

System.out.println(proxy.div(100, 0));

}

}

优点:这种方式已经解决我们前面所有日记需要的问题。非常的灵活。而且可以方便的在后期进行维护和升级。

缺点:当然使用jdk动态代理,需要有接口。如果没有接口。就无法使用jdk动态代理。

AOP编程的专业术语

通知(Advice)

通知就是增强的代码。比如前置增强的代码。后置增强的代码。异常增强代码。这些就叫通知

切面(Aspect)

切面就是包含有通知代码的类叫切面。

横切关注点

横切关注点,就是我们可以添加增强代码的位置。比如前置位置,后置位置,异常位置。和返回值位置。这些都叫横切关注点。

目标(Target)

目标对象就是被关注的对象。或者被代理的对象。

代理(Proxy)

为了拦截目标对象方法,而被创建出来的那个对象,就叫做代理对象。

连接点(Joinpoint)

连接点指的是横切关注点和程序代码的连接,叫连接点。

切入点(pointcut)

切入点指的是用户真正处理的连接点,叫切入点。

在Spring中切入点通过org.springframework.aop.Pointcut 接口进行描述,它使用类和方法作为连接点的查询条件。

图解AOP专业术语:

在这里插入图片描述

使用Spring实现AOP简单切面编程

创建一个java工程:

在这里插入图片描述

导入jar包:

com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar

commons-logging-1.1.3.jar

spring-aop-4.3.18.RELEASE.jar

spring-aspects-4.3.18.RELEASE.jar

spring-beans-4.3.18.RELEASE.jar

spring-context-4.3.18.RELEASE.jar

spring-core-4.3.18.RELEASE.jar

spring-expression-4.3.18.RELEASE.jar

配置文件信息:

<?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-4.3.xsd

http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">

<context:component-scan base-package=“com”></context:component-scan>

aop:aspectj-autoproxy</aop:aspectj-autoproxy>

bean对象

@Component

public class Calculator implements Calculate {

@Override

public int add(Integer num1, Integer num2) {

int result = num1 + num2;

System.out.println(“目标方法 add被执行了”);

return result;

}

@Override

public int add(Integer num1, Integer num2, Integer num3) {

int result = num1 + num2 + num3;

System.out.println(“目标方法 add被执行了”);

return result;

}

@Override

public int div(Integer num1, Integer num2) {

System.out.println(“目标方法 div被执行了”);

int result = num1 / num2;

return result;

}

}

@Aspect

@Component

public class LogUtils {

/**

  • @Before是前置通知

*/

@Before(value=“execution(public int com.pojo.Calculator.add(Integer, Integer))”)

// 前置通知===前置增强

public static void logBefore() {

System.out.println(“前置通知 : 方法名:xxxx. 参数是:args”);

}

}

测试代码:

public class SpringTest {

@Test

public void test1() throws Exception {

// 创建Spring IOC 容器对象

ApplicationContext applicationContext = new ClassPathXmlApplicationContext(“applicationContext.xml”);

Calculate calculate = (Calculate) applicationContext.getBean(“calculator”);

calculate.add(100, 100);

}

}

Spring切面中的代理对象

在Spring中,可以对有接口的对象和无接口的对象分别进行代理。在使用上有些细微的差别。

  1. 如果被代理的对象实现了接口。在获取对象的时候,必须要以接口来接收返回的对象。

在这里插入图片描述

  1. 如果被代理对象,如果没有实现接口。获取对象的时候使用对象类型本身

在这里插入图片描述

Spring的切入点表达式

@PointCut切入点表达式语法格式是:

execution(访问权限 返回值类型 方法全限定名(参数类型列表))

execution(public int com.atguigu.pojo.Calculator.add(Integer, Integer))

限定符:

_表示任意的意思:

1)匹配某全类名下,任意或多个方法。

execution(public int com.atguigu.pojo.Calculator._(Integer, Integer))

表示匹配任意的方法

2)在Spring中只有public权限能拦截到,访问权限可以省略(访问权限不能写*)。

execution(int com.atguigu.pojo.Calculator.*(Integer, Integer))

可以省略public访问权限

3)匹配任意类型的返回值,可以使用 * 表示

execution(public * com.atguigu.pojo.Calculator.*(Integer, Integer))

表示可以接受任意返回值类型

4)匹配任意子包。

execution(public int com.atguigu.*.Calculator.add(Integer, Integer))

匹配任意子包

5)任意类型参数

execution(public int com.atguigu.pojo.Calculator.add(Integer, *))

表示第二个参数是任意类型的参数

…:可以匹配多层路径,或任意多个任意类型参数

1)任意层级的包

execution(public int com…pojo.Calculator.add(Integer, Integer))

表示com和pojo之间可以有任意层级的包。

2)任意类型的参数

execution(public int com.atguigu.pojo.Calculator.add(…))

不关心参数的个数,和参数的类型。

模糊匹配:

// 表示任意返回值,任意方法全限定符,任意参数

execution(* _(…))

// 表示任意返回值,任意包名+任意方法名,任意参数

execution(_ .(…))

精确匹配:

execution(public int com.atguigu.aop.Calculator.add(int, int))

切入点表达式连接:&& 、||

// 表示需要同时满足两个表达式

@Before(“execution(public int com.atguigu.aop.Calculator.add(int, int))”

+ " && "

  • “execution(public * com.atguigu.aop.Calculator.add(…))”)

// 表示两个条件只需要满足一个,就会被匹配到

@Before(“execution(public int com.atguigu.aop.Calculator.add(int, int))”

+ " || "

+ “execution(public * com.atguigu.aop.Calculator.a*(int))”)

9.9、Spring通知的执行顺序

Spring通知的执行顺序是:

正常情况:

前置通知====>>>>目标方法====>>>>后置通知=====>>>>返回值之后

异常情况:

前置通知====>>>>目标方法====>>>>后置通知=====>>>>抛异常通知

@Aspect

@Component

public class LogUtils {

/**

* @Before是前置通知

_/

@Before(value = “execution(public int com.atguigu.pojo.Calculator._(Integer, Integer))”)

// 前置通知===前置增强

public static void logBefore() {

System.out.println(“前置通知 : 方法名:xxxx. 参数是:args”);

}

/**

* @After 后置通知

_/

@After(value = “execution(public int com.atguigu.pojo.Calculator._(Integer, Integer))”)

public static void logAfter() {

System.out.println(“后置通知: 方法名:. 参数是:”);

}

/**

* 返回值通知

_/

@AfterReturning(value = “execution(public int com.atguigu.pojo.Calculator._(Integer, Integer))”)

public static void logAfterReturning() {

System.out.println(“返回通知: 方法名:. 返回值是:”);

}

/**

* 异常通知

_/

@AfterThrowing(value = “execution(public int com.atguigu.pojo.Calculator._(Integer, Integer))”)

public static void logAfterThrowing() {

System.out.println(“异常通知: 方法名:. 异常信息是:”);

}

}

获取连接点信息

JoinPoint 是连接点的信息。

只需要在通知方法的参数中,加入一个JoinPoint参数。就可以获取到拦截方法的信息。

注意:是org.aspectj.lang.JoinPoint这个类。

/**

  • @Before是前置通知

*/

@Before(value = “execution(public int com.atguigu.pojo.Calculator.*(Integer, Integer))”)

// 前置通知===前置增强

public static void logBefore(JoinPoint jp) {

// jp.getSignature().getName() 获取方法名

// jp.getArgs() 获取目标方法传递的参数

System.out.println(“前置通知 : 方法名:” + jp.getSignature().getName() + “. 参数是:” + Arrays.asList(jp.getArgs()));

}

获取拦截方法的返回值和抛的异常信息

获取方法返回的值分为两个步骤:

1、在返回值通知的方法中,追加一个参数 Object result

2、然后在@AfterReturning注解中添加参数returning=“参数名”

/**

  • 返回值通知

  • returning属性设置用哪个参数来接收返回值

*/

@AfterReturning(value = “execution(public int com.atguigu.pojo.Calculator.*(Integer, Integer))”,returning=“result”)

public static void logAfterReturning(JoinPoint jp, Object result) {

System.out.println(“返回通知: 方法名:” + jp.getSignature().getName() + “. 返回值是:” + result);

}

获取方法抛出的异常分为两个步骤:

1、在异常通知的方法中,追加一个参数Exception exception

2、然后在@AfterThrowing 注解中添加参数 throwing=“参数名”

/**

  • 异常通知

  • throwing=“e” 表示使用参数Throwable e来接收抛出的异常

*/

@AfterThrowing(value = “execution(public int com.pojo.Calculator.*(Integer, Integer))”,throwing=“e”)

public static void logAfterThrowing(JoinPoint jp,Throwable e) {

System.out.println(“异常通知: 方法名:” + jp.getSignature().getName() + “. 异常信息是:” + e);

}

Spring的环绕通知

1、环绕通知使用@Around注解。

2、环绕通知如果和其他通知同时执行。环绕通知会优先于其他通知之前执行。

3、环绕通知一定要有返回值(环绕如果没有返回值。后面的其他通知就无法接收到目标方法执行的结果)。

4、在环绕通知中。如果拦截异常。一定要往外抛。否则其他的异常通知是无法捕获到异常的。

/**

  • @throws Throwable

  • @Around 注解表示环绕通知

  • 1 环绕通知 执行顺序优先于 普通通知(默认情况)

  • 2 环绕通知方法一定要有返回值。而且这个返回值一定是目标方法的返回值。

  • 3 环绕通知方法中收到异常后,一定要往外抛

*/

@Around(value = “execution(public int com.pojo.Calculator.*(Integer, Integer))”)

public static Object around(ProceedingJoinPoint pjp) throws Throwable {

Object result = null;

try {

try {

System.out.println(“环绕的前置通知”);

// 调用目标方法

result = pjp.proceed();

} finally {

System.out.println(“环绕的后置通知”);

}

System.out.println(“环绕的返回通知:” + result);

} catch (Throwable e) {

System.out.println(“环绕的异常通知:” + e);

throw e;// 普通的异常通知就会收到异常

}

return result;// 普通的返回通知,就会收到返回值

}

切入点表达式的复用

* 切入点表达式的复用

* 第一步:定义一个方法

* 第二步: 在方法上,使用@Pointcut定义一个切入点表达式

* 第三步:在需要复用切入点表达式的地方换成方法调用

/**

  • 切入点表达式的复用

  • 第一步:定义一个方法

  • 第二步: 在方法上,使用@Pointcut定义一个切入点表达式

  • 第三步:在需要复用切入点表达式的地方换成方法调用

*/

@Pointcut(value=“execution(public int com.pojo.Calculator.*(Integer, Integer))”)

public static void pointcut1() {}

/**

  • @Before是前置通知

*/

@Before(value = “pointcut1()”)

// 前置通知===前置增强

public static void logBefore(JoinPoint jp) {

System.out.println(“前置通知 : 方法名:” + jp.getSignature().getName() + “. 参数是:” + Arrays.asList(jp.getArgs()));

}

多个通知的执行顺序

当我们有多个切面,多个通知的时候:

1、通知的执行顺序默认是由切面类的字母先后顺序决定。

2、在切面类上使用@Order注解决定通知执行的顺序(值越小,越先执行)

在这里插入图片描述

在这里插入图片描述

如何基于xml配置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: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-4.3.xsd

http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">

<context:component-scan base-package=“com”></context:component-scan>

aop:config

<aop:aspect ref=“logUtils”>

<aop:pointcut expression=“execution(public int com.pojo.Calculator.*(Integer, Integer))”

id=“pointcut1”/>

<aop:before method=“logBefore”

pointcut=“execution(public int com.pojo.Calculator.*(Integer, Integer))”/>

<aop:after method=“logAfter” pointcut-ref=“pointcut1”/>

<aop:after-returning method=“logAfterReturning”

pointcut-ref=“pointcut1” returning=“result”

/>

<aop:after-throwing method=“logAfterThrowing”

pointcut-ref=“pointcut1” throwing=“e”

/>

</aop:aspect>

</aop:config>

Spring之数据访问

Spring数据访问工程环境搭建

创建一个java工程

在这里插入图片描述

导入jar包:

commons-logging-1.1.3.jar

druid-1.1.9.jar

mysql-connector-java-5.1.37-bin.jar

spring-aop-4.3.18.RELEASE.jar

spring-beans-4.3.18.RELEASE.jar

spring-context-4.3.18.RELEASE.jar

spring-core-4.3.18.RELEASE.jar

spring-expression-4.3.18.RELEASE.jar

spring-jdbc-4.3.18.RELEASE.jar

spring-orm-4.3.18.RELEASE.jar

spring-test-4.3.18.RELEASE.jar

spring-tx-4.3.18.RELEASE.jar

jdbc.properties属性配置文件:

url=jdbc:mysql://localhost:3306/book

user=root

password=root

driverClassName=com.mysql.jdbc.Driver

initialSize=5

maxActive=10

applicationContext.xml配置文件:

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns=“http://www.springframework.org/schema/beans”

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注Java)
img

我的面试宝典:一线互联网大厂Java核心面试题库

以下是我个人的一些做法,希望可以给各位提供一些帮助:

整理了很长一段时间,拿来复习面试刷题非常合适,其中包括了Java基础、异常、集合、并发编程、JVM、Spring全家桶、MyBatis、Redis、数据库、中间件MQ、Dubbo、Linux、Tomcat、ZooKeeper、Netty等等,且还会持续的更新…可star一下!

image

283页的Java进阶核心pdf文档

Java部分:Java基础,集合,并发,多线程,JVM,设计模式

数据结构算法:Java算法,数据结构

开源框架部分:Spring,MyBatis,MVC,netty,tomcat

分布式部分:架构设计,Redis缓存,Zookeeper,kafka,RabbitMQ,负载均衡等

微服务部分:SpringBoot,SpringCloud,Dubbo,Docker

image

还有源码相关的阅读学习

image

一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!

AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算

内容对你有帮助,可以添加V获取:vip1024b (备注Java)**
[外链图片转存中…(img-ymmPaMUH-1712189599755)]

我的面试宝典:一线互联网大厂Java核心面试题库

以下是我个人的一些做法,希望可以给各位提供一些帮助:

整理了很长一段时间,拿来复习面试刷题非常合适,其中包括了Java基础、异常、集合、并发编程、JVM、Spring全家桶、MyBatis、Redis、数据库、中间件MQ、Dubbo、Linux、Tomcat、ZooKeeper、Netty等等,且还会持续的更新…可star一下!

[外链图片转存中…(img-bLQdhkEA-1712189599756)]

283页的Java进阶核心pdf文档

Java部分:Java基础,集合,并发,多线程,JVM,设计模式

数据结构算法:Java算法,数据结构

开源框架部分:Spring,MyBatis,MVC,netty,tomcat

分布式部分:架构设计,Redis缓存,Zookeeper,kafka,RabbitMQ,负载均衡等

微服务部分:SpringBoot,SpringCloud,Dubbo,Docker

[外链图片转存中…(img-bVo8muDS-1712189599756)]

还有源码相关的阅读学习

[外链图片转存中…(img-I6viuMcf-1712189599756)]

一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!

AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算

  • 27
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值