1.Spring常用的概念

Joinpoint(连接点):

所谓连接点是指那些被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点。

Pointcut(切入点):

所谓切入点是指我们要对哪些Joinpoint进行拦截的定义。

Advice(通知/增强):

所谓通知是指拦截到Joinpoint之后所要做的事情就是通知。

通知的类型:前置通知,后置通知,异常通知,最终通知,环绕通知。

Introduction(引介):

引介是一种特殊的通知在不修改类代码的前提下, Introduction可以在运行期为类动态地添加一些方法或Field。

Target(目标对象):

代理的目标对象。

Weaving(织入):

是指把增强应用到目标对象来创建新的代理对象的过程。

spring采用动态代理织入,而AspectJ采用编译期织入和类装载期织入。

Proxy(代理):

一个类被AOP织入增强后,就产生一个结果代理类。

Aspect(切面):

是切入点和通知(引介)的结合。

2.使用xml配置Spring 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"> <!-- 配置service -->
<bean id="customerService" class="com.itheima.service.impl.CustomerServiceImpl"></bean>
<!-- 基于xml的aop配置步骤 :要想使用spring的aop,必须导入aop的jar包-->
<!-- 第一步:把通知类交给spring来管理 -->
<bean id="logger" class="com.itheima.utils.Logger"></bean> <!-- 第二步:导入aop名称空间,并且使用aop:config开始aop的配置 -->
<aop:config>
<!-- 定义通用的切入点表达式,如果写在aop:aspct标签外部,则表示所有切面可用 -->
<aop:pointcut expression="execution(* com.itheima.service.impl.*.*(..))" id="pt1"/> <!-- 第三步:使用aop:aspect配置切面 id属性用于给切面提供一个唯一标识。ref属性:用于应用通知Bean的id-->
<aop:aspect id="logAdvice" ref="logger">
<!-- 第四步:配置通知的类型,指定增强的方法何时执行。method属性:用于指定增强的方法名称 pointcut属性:用于指定切入点表达式。-->
<!-- 切入点表达式:
关键字:execution(表达式)
表达式写法:
访问修饰符 返回值 包名.包名...类名.方法名(参数列表)
全匹配方式:
public void com.itheima.service.impl.CustomerServiceImpl.saveCustomer()
访问修饰符可以省略
void com.itheima.service.impl.CustomerServiceImpl.saveCustomer()
返回值可以使用通配符,表示任意返回值。通配符是*
* com.itheima.service.impl.CustomerServiceImpl.saveCustomer()
包名可以使用通配符,表示任意包。但是,有几个包就需要写几个*
*.*.*.*.CustomerServiceImpl.saveCustomer()
包名可以使用..表示当前包及其子包
* com..CustomerServiceImpl.saveCustomer()
类名和方法名都可以使用通配符
* com..*.*()
参数列表可以使用具体类型,来表示参数类型
基本类型直接写类型名称:int
引用类型必须是包名.类名。 java.lang.Integer
参数列表可以使用通配符,表示任意参数类型,但是必须有参数
* com..*.*(*)
参数列表可以使用..表示有无参数均可,有参数可以是任意类型
* com..*.*(..)
全通配方式:
* *..*.*(..)
实际开发中,我们一般情况下,我们都是对业务层方法进行增强:
所以写法:* com.itheima.service.impl.*.*(..) -->
<!-- 配置前置通知: 永远在切入点方法执行之前执行
<aop:before method="beforePrintLog" pointcut-ref="pt1"/>-->
<!-- 配置后置通知: 切入点方法正常执行之后执行
<aop:after-returning method="afterReturningPrintLog" pointcut-ref="pt1"/>-->
<!-- 配置异常通知: 切入点方法执行产生异常之后执行。它和后置通知永远只能执行一个
<aop:after-throwing method="afterThrowingPrintLog" pointcut-ref="pt1"/>-->
<!-- 配置最终通知:无论切入点方法是否正常执行,它都会在其后面执行
<aop:after method="afterPrintLog" pointcut-ref="pt1"/> --> <!-- 配置环绕通知 -->
<aop:around method="aroundPrintLog" pointcut-ref="pt1"/>
<!-- 定义通用的切入点表达式:如果是写在了aop:aspect标签内部,则表示只有当前切面可用
<aop:pointcut expression="execution(* com.itheima.service.impl.*.*(..))" id="pt1"/>-->
</aop:aspect>
</aop:config>
</beans>

环绕通知出现的问题

    /**
* 环绕通知
* 问题:
* 当我们配置了环绕通知之后,切入点方法没有执行,而环绕通知里的代码执行了。
* 分析:
* 由动态代理可知,环绕通知指的是invoke方法,并且里面有明确的切入点方法调用。而我们现在的环绕通知没有明确切入点方法调用。
* 解决:
* spring为我们提供了一个接口:ProceedingJoinPoint。该接口可以作为环绕通知的方法参数来使用。
* 在程序运行时,spring框架会为我们提供该接口的实现类,供我们使用。
* 该接口中有一个方法,proceed(),它的作用就等同于method.invoke方法,就是明确调用业务层核心方法(切入点方法)
*
* 环绕通知:
* 它是spring框架为我们提供的一种可以在代码中手动控制通知方法什么时候执行的方式。
*/
public Object aroundPrintLog(ProceedingJoinPoint pjp){
Object rtValue = null;
try {
System.out.println("Logger中的aroundPrintLog方法开始记录日志了。。。。前置");
rtValue = pjp.proceed();
System.out.println("Logger中的aroundPrintLog方法开始记录日志了。。。。后置");
} catch (Throwable e) {
System.out.println("Logger中的aroundPrintLog方法开始记录日志了。。。。异常");
e.printStackTrace();
}finally{
System.out.println("Logger中的aroundPrintLog方法开始记录日志了。。。。最终");
} return rtValue;
}

3.使用注解配置spring AOP的实现

    1.添加Spring对注解AOP的支持,使用aspectj

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

    2.实现代码

package com.itheima.utils;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component; /**
* 一个用于记录日志的类
* @author zhy
*
*/
@Component("logger")
@Aspect//配置了切面
public class Logger { @Pointcut("execution(* com.itheima.service.impl.*.*(..))")
private void pt1(){} /**
* 前置通知
*/
//@Before("pt1()")
public void beforePrintLog(){
System.out.println("前置:Logger中的beforePrintLog方法开始记录日志了。。。。");
} /**
* 后置通知
*/
//@AfterReturning("pt1()")
public void afterReturningPrintLog(){
System.out.println("后置:Logger中的afterReturningPrintLog方法开始记录日志了。。。。");
} /**
* 异常通知
*/
//@AfterThrowing("pt1()")
public void afterThrowingPrintLog(){
System.out.println("异常:Logger中的afterThrowingPrintLog方法开始记录日志了。。。。");
} /**
* 最终通知
*/
//@After("pt1()")
public void afterPrintLog(){
System.out.println("最终:Logger中的afterPrintLog方法开始记录日志了。。。。");
} /**
* 环绕通知
* 问题:
* 当我们配置了环绕通知之后,切入点方法没有执行,而环绕通知里的代码执行了。
* 分析:
* 由动态代理可知,环绕通知指的是invoke方法,并且里面有明确的切入点方法调用。而我们现在的环绕通知没有明确切入点方法调用。
* 解决:
* spring为我们提供了一个接口:ProceedingJoinPoint。该接口可以作为环绕通知的方法参数来使用。
* 在程序运行时,spring框架会为我们提供该接口的实现类,供我们使用。
* 该接口中有一个方法,proceed(),它的作用就等同于method.invoke方法,就是明确调用业务层核心方法(切入点方法)
*
* 环绕通知:
* 它是spring框架为我们提供的一种可以在代码中手动控制通知方法什么时候执行的方式。
*/
@Around("pt1()")
public Object aroundPrintLog(ProceedingJoinPoint pjp){
Object rtValue = null;
try {
System.out.println("Logger中的aroundPrintLog方法开始记录日志了。。。。前置");
rtValue = pjp.proceed();
System.out.println("Logger中的aroundPrintLog方法开始记录日志了。。。。后置");
} catch (Throwable e) {
System.out.println("Logger中的aroundPrintLog方法开始记录日志了。。。。异常");
e.printStackTrace();
}finally{
System.out.println("Logger中的aroundPrintLog方法开始记录日志了。。。。最终");
} return rtValue;
} }

    3.使用全注解方式实现

package com.dyh.ioc.base;

import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.stereotype.Component; //即使用jdk默认代理模式,AspectJ代理模式是CGLIB代理模式
//如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP
//如果目标对象实现了接口,可以强制使用CGLIB实现AOP (此例子我们就是强制使用cglib实现aop)
//如果目标对象没有实现了接口,必须采用CGLIB库,spring会自动在JDK动态代理和CGLIB之间转换 //用于定义配置类,可替换xml配置文件
@Configuration
//开启AspectJ 自动代理模式,如果不填proxyTargetClass=true,默认为false,
@EnableAspectJAutoProxy(proxyTargetClass=true)
//扫描注入类
@ComponentScan(basePackages = "com.dyh.ioc.*")
@Component
@Aspect
public class AopAspectConfiguration {
//声明切入点
//第一个*表示 方法 返回值(例如public int)
//第二个* 表示方法的全限定名(即包名+类名)
//perform表示目标方法参数括号两个.表示任意类型参数
//方法表达式以“*”号开始,表明了我们不关心方法返回值的类型。然后,我们指定了全限定类名和方法名。对于方法参数列表,
//我们使用两个点号(..)表明切点要选择任意的perform()方法,无论该方法的入参是什么
//execution表示执行的时候触发
@Pointcut("execution(* *(..))")
public void point(){
//该方法就是一个标识方法,为pointcut提供一个依附的地方
} @Before("point()")
public void before(){
System.out.println("Before");
}
@After("point()")
public void after(){
System.out.println("After");
}
}

-----------------------

  spring AOP 和 AspectJ 都可以实现 切面编程 ,因此spring也可以集成AspectJ来实现切面编程,两者没什么太大的关系

  Spring AOP有两种实现方式:

    基于接口的动态代理(Dynamic Proxy)

    基于子类化的CGLIB代理

  区别在于两者实现AOP的底层原理不太一样:

  • Spring AOP: 基于代理(Proxying)
  • AspectJ: 基于字节码操作(Bytecode Manipulation)

-------------------------------------------------------------------------------------------------

AspectJ是一套独立的面向切面框架,

优点:支持静态织入代码,性能更优.

缺点:静态织入丧失了灵活,需要学习新的语法.

Spring Aop是SprinG基于Java Proxy进行的一层封装,Spring中无论是XML(注解)定义的切面信息,都只是对Meta数据的定义,最终核心类:CglibProxy/JdyDynamicAopProxy.

优点:动态织入,产生了新的Class.能做到动态的增加或减少切面.

缺点:动态织入带来的性能会有所下降,如果,控制不当,会产生大量重复Class.造成GC頻繁. CglibAopProxy中就用到了Cglib动态产生字节码,因为:InvocationHandler只能支持Interface.

spring AOP的学习的更多相关文章

  1. Spring AOP体系学习总结:

    二.Spring AOP体系学习总结: 要理解AOP整体的逻辑需要理解一下Advice,Pointcut,Advisor的概念以及他们的关系. Advice是为Spring Bean提供增强逻辑的接口 ...

  2. Spring AOP体系学习总结

    要理解AOP整体的逻辑需要理解一下Advice,Pointcut,Advisor的概念以及他们的关系.  Advice是为Spring Bean提供增强逻辑的接口,提供了多种方法增强的方式,比如前置, ...

  3. 笔记-spring aop 原理学习2

    InstantiationAwareBeanPostProcessor AnnotationAwareAspectJAutoProxyCreator https://blog.csdn.net/qq_ ...

  4. spring aop 原理学习

    @EnableAspectJAutoProxy: @Import(AspectJAutoProxyRegistrar.class) 实际是创建了一个以org.springframework.aop.c ...

  5. 关于spring AOP的学习

    比较好的帖子http://www.cnblogs.com/xing901022/p/4265544.html

  6. 【目录】Spring 源码学习

    [目录]Spring 源码学习 jwfy 关注 2018.01.31 19:57* 字数 896 阅读 152评论 0喜欢 9 用来记录自己学习spring源码的一些心得和体会以及相关功能的实现原理, ...

  7. Spring AOP 知识整理

    通过一个多月的 Spring AOP 的学习,掌握了 Spring AOP 的基本概念.AOP 是面向切面的编程(Aspect-Oriented Programming),是基于 OOP(面向对象的编 ...

  8. Spring 源码学习笔记11——Spring事务

    Spring 源码学习笔记11--Spring事务 Spring事务是基于Spring Aop的扩展 AOP的知识参见<Spring 源码学习笔记10--Spring AOP> 图片参考了 ...

  9. 学习AOP之深入一点Spring Aop

    上一篇<学习AOP之认识一下SpringAOP>中大体的了解了代理.动态代理及SpringAop的知识.因为写的篇幅长了点所以还是再写一篇吧.接下来开始深入一点Spring aop的一些实 ...

随机推荐

  1. 求强连通分量Tarjan算法

    ]; // 时间戳 ; // 时间 ]; // 节点u所能访问到的最小时间戳 ]; // 节点u是否在栈中. ]; ; // 我们维护的信息. ]; // 给节点染色, 同一个连通块的节点应该是同一个 ...

  2. HDU2036:改革春风吹满地

    Problem Description " 改革春风吹满地, 不会AC没关系; 实在不行回老家, 还有一亩三分地. 谢谢!(乐队奏乐)" 话说部分学生心态极好,每天就知道游戏,这次 ...

  3. 2017.4.7 Sprng MVC工作流程描述图

    图一: 图二: Spring工作流程描述         1. 用户向服务器发送请求,请求被Spring 前端控制Servelt DispatcherServlet捕获:       2. Dispa ...

  4. django-models层

    ----https://www.cnblogs.com/liuqingzheng/articles/9472723.html 一.ORM简介 查询数据层次图解:如果操作mysql,ORM是在pymys ...

  5. Python IDLE theme

    #转自 http://www.2cto.com/os/201507/418532.html #win10+python3.5.2 #保护视力 .idlerc 目录下新建名为 config-highli ...

  6. 【NOI2014】【BZOJ3669】【UOJ#3】魔法森林

    我学会lct辣 原题: 为了得到书法大家的真传,小E同学下定决心去拜访住在魔法森林中的隐士.魔法森林可以被看成一个包含个N节点M条边的无向图,节点标号为 1…n1…n,边标号为1…m1…m.初始时小E ...

  7. OpenGL编程-OpenGL框架-win32项目

    在win32项目中开发的程序 小知识: 控制台应用程序运行就是dos的界面 项目一般采用了可视化开发 开发出来的东西就像QQ之类的 是有窗口界面的 程序运行结果是这样的 源代码:对第45行进行覆盖 # ...

  8. Scala下划线_使用

    下划线这个符号几乎贯穿了任何一本Scala编程书籍,并且在不同的场景下具有不同的含义,绕晕了不少初学者.正因如此,下划线这个特殊符号无形中增加Scala的入门难度.本文希望帮助初学者踏平这个小山坡. ...

  9. Monitor Minio server with Prometheus

    转自:https://blog.minio.io/monitor-minio-server-with-prometheus-4ed537abcb74 Prometheus is an open sou ...

  10. MSP430F2272 Flash

    The collected information is listed below during flash of MSP430 development. MSP430F2272: 32KB + 25 ...