面向切面编程SpringAop入门案例和实现机制

2023-11-12

代理与SpringAop

  1. springAop概述

  2. SpringAop术语

  3. SpringAop的实现机制

    springAop概述

    AOP 是 OOP 的延续,是 Aspect Oriented Programming 的缩写,意思是面向切面编程。可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术。AOP设计模式孜孜不倦追求的是调用者和被调用这之间的解耦,AOP 可以说也是这种目标的一种实现。本质上aop就是代理思想实现的

    我们现在做的一些非业务,如:日志、事务、安全等都会写在业务代码中(也即是说,这些非业务类横切与业务类),但这些代码往往是重复,复制-粘贴式的代码会给程序带来不便,AOP 就实现了把这些业务与需求分开来做。这种解决的方式也成代理机制。

    SpringAop术语

    1. 连接点(join Point):程序执行的某个特定位置,比如(类开始初始化前,初始化后,方法前,方法后,异常后) 一个类或者一段程序代码拥有一些具有边界的特定点,这些特定点称为连接点
    2. 切点(pointcut):每个程序都拥有多个连接点,比如一个类有2个方法,这2个方法就是连接点,连接点就是程序中具体的事物,AOP 通过切点来定位特定的连接点,连接点相当于数据库中的记录,而切点相当于是查询记录的条件。在程序中,切点是连接点位置的集合
    3. 增强(advice):就是我们要具体做的事情,也就在原有的方法之上添加新的能力
    4. 目标对象:就是我们要增强的类;
    5. 引入:特殊的增强,为类添加属性和方法。哪怕这个类没有任何的属性和方法我们也可以通过aop去添加方法和属性实现逻辑
    6. 织入(weaving):就是把增强添加到目标类具体的连接点上的过程
    7. 代理:一个类被AOP织入增强后产生的结果类,他是原类和增强后的代理类,更具代理s不同的方式,代理类可能是和原类具有相同接口的类,也可能是原类的子类
    8. 切面(Aspect):切面由切点和增强组成,他既包含横切的定义,也包括了连接点的定义,spring aop就是负责实施切面的框架,他将切面定义为横切逻辑织入到切面所指定的连接点

    SpringAop的实现机制

JDK实现动态代理

代理目标对象接口类:
//目标对象接口
public interface TargetInterface {

    public void save();
}

代理目标对象实现类
public class TargetInterfaceImpl implements TargetInterface {
    @Override
    public void save() {
        System.out.println("save running >>>>>");
    }
}

通知/增强处理类
public class Advice {


    public void before(){
        System.out.println("前置增强方法>>>>");
    }

    public void afterRunning(){
        System.out.println("后置增强方法>>>>");
    }
}

测试类
//测试类
public class ProxyText {

    public static void main(String[] args) {

        //目标对象
        final TargetInterface target = new TargetInterfaceImpl();

        //获得增强对象

        final Advice advice = new Advice();

                //返回值就是动态生成的代理对象
               TargetInterface proxy = (TargetInterface) Proxy.newProxyInstance(
                        target.getClass().getClassLoader(), //目标对象的类加载器
                        target.getClass().getInterfaces(),//目标对象相同的接口字节码对象数组
                        new InvocationHandler() {
                            //调用代理对象,实质执行的是invoke方法
                            public Object invoke(
                                Object proxy,
                                Method method,
                                Object[] args
                            ) throws Throwable {
                                advice.before();//前置增强
                                Object invoke = method.invoke(target, args);//执行目标方法
                                advice.afterRunning();  //后置增强
                                return invoke;
                            }
                        }

                );

               //调用代理对象方法
        proxy.save();
    }
}

运行结果
前置增强方法>>>>
save running >>>>>
后置增强方法>>>>

Process finished with exit code 0

CGlib实现动态代理:

代理目标对象类
public class Target {

    public void save() {
        System.out.println("save running >>>>>");
    }
}

通知/增强处理类
public class Advice {


    public void before(){
        System.out.println("前置增强方法>>>>");
    }

    public void afterRunning(){
        System.out.println("后置增强方法>>>>");
    }
}
测试类
    public static void main(String[] args) {

        //目标对象
        final Target target = new Target();
         //增强对象
        final Advice advice = new Advice();


        //返回值就是动态生成的代理对象 基于cglib
        //1、创建增强器
        Enhancer enhancer = new Enhancer();
        //2、设置父类(目标)
        enhancer.setSuperclass(Target.class);
        //3、设置回调
        enhancer.setCallback(new MethodInterceptor() {
            @Override
            public Object intercept(
                Object proxy, 
                Method method,
                Object[] args,
                MethodProxy methodProxy
            ) throws Throwable {
                //执行前置
                advice.before();
                Object invoke = method.invoke(target, args);//执行目标
                advice.afterRunning();//执行后置
                return invoke;
            }
        });
        //4、创建代理对象
        Target target1 =(Target) enhancer.create();
        target1.save();
    }
}

运行结果
前置增强方法>>>>
save running >>>>>
后置增强方法>>>>

Process finished with exit code 0

springAop代理的实现(xml):

创建目标接口和目标实现类(内部有切点)
public interface TargetInterface {

    public void save();
}

public class Target implements TargetInterface {

    public void save() {
        System.out.println("save running >>>>>");
    }
}

创建切面类((内部有增强方法)

public class MyAspect {

    public void before(){
        System.out.println("前置增强 >>>>>>");
    }

    public void afterReturning(){
        System.out.println("后置增强 >>>>>>");
    }
}

将目标类和切面类的对象创建权交给 spring
<!--配置目标类-->
<bean id="target" class="com.liu.aop.Target"></bean>
<!--配置切面类-->
<bean id="myAspect" class="com.liu.aop.MyAspect"></bean>

在 applicationContext.xml 中配置织入关系
<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/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/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
配置切点表达式和前置增强的织入关系
<aop:config>
<!--引用myAspect的Bean为切面对象-->
<aop:aspect ref="myAspect">
<!--配置Target的method方法执行时要进行myAspect的before方法前置增强-->
<aop:before method="before" pointcut="execution(public void 
com.liu.aop.Target.save())"></aop:before>
<!--配置Target的method方法执行时要进行myAspect的after方法后置增强-->
<aop:after method="afterReturning" pointcut="execution(public void 
com.liu.aop.Target.save())"></aop:before>
 
</aop:aspect>
</aop:config>
测试类
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class AopTest {
    @Autowired
    private TargetInterface target;
    @Test
    public void test1(){
        target.save();
    }
}
运行结果
前置增强 >>>>>>
save running >>>>>
后置增强 >>>>>>

springAop代理的实现(注解)

创建目标接口和目标类(内部有切点)
public interface TargetInterface {
      void method();
}

public class Target implements TargetInterface {
@Override
     public void method() {
     	System.out.println("Target running....");
     }
}
创建切面类(内部有增强方法)
public class MyAspect {
//前置增强方法
	public void before(){
		System.out.println("前置代码增强.....");
	}
    //后置增强方法
	public void afterReturning(){
		System.out.println("后置代码增强.....");
	}
    
}
将目标类和切面类的对象创建权交给 spring
Component("target")
public class Target implements TargetInterface {
	@Override
	public void method() {
		System.out.println("Target running....");
	}
}
@Component("myAspect")
public class MyAspect {
	public void before(){
		System.out.println("前置代码增强.....");
	}
	public void afterReturning(){
		System.out.println("后置代码增强.....");
	}
}
在切面类中使用注解配置织入关系
@Component("myAspect")
@Aspect
public class MyAspect {
    
    //定义一个切点表达式
    @Pointcut("execution(* com.liu.proxy.anno.*.*(..))")
    public void pointcut(){}

    @Before("MyAspect.pointcut()")
	public void before(){
		System.out.println("前置代码增强.....");
	}
    
    @After("MyAspect.pointcut()")
    public void afterReturning(){
		System.out.println("后置代码增强.....");
	}
}

测试代码
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class AopTest {
	@Autowired	
	private TargetInterface target;
    
	@Test
	public void test1(){
	target.method();	
	}
}

前置代码增强 >>>>>>
Target running >>>>>
后置代码增强 >>>>>>

切点修饰语法

表达式语法:

execution([修饰符] 返回值类型 包名.类名.方法名(参数))
  • 访问修饰符可以省略
  • 返回值类型、包名、类名、方法名可以使用星号* 代表任意
  • 包名与类名之间一个点 . 代表当前包下的类,两个点 … 表示当前包及其子包下的类
  • 参数列表可以使用两个点 … 表示任意个数,任意类型的参数列表

例如:

execution(public void com.liu.aop.Target.method())
execution(void com.liu.aop.Target.*(..))
execution(* com.liu.aop.*.*(..))
execution(* com.liu.aop..*.*(..))
execution(* *..*.*(..))
 *                             _ooOoo_
 *                            o8888888o
 *                            88" . "88
 *                            (| -_- |)
 *                            O\  =  /O
 *                         ____/`---'\____
 *                       .'  \\|     |//  `.
 *                      /  \\|||  :  |||//  \
 *                     /  _||||| -:- |||||-  \
 *                     |   | \\\  -  /// |   |
 *                     | \_|  ''\---/''  |   |
 *                     \  .-\__  `-`  ___/-. /
 *                   ___`. .'  /--.--\  `. . __
 *                ."" '<  `.___\_<|>_/___.'  >'"".
 *               | | :  `- \`.;`\ _ /`;.`/ - ` : | |
 *               \  \ `-.   \_ __\ /__ _/   .-` /  /
 *          ======`-.____`-.___\_____/___.-`____.-'======
 *                             `=---='
 *          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    

欢迎访问我的csdn博客,我们一起成长!!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

面向切面编程SpringAop入门案例和实现机制 的相关文章

  • 如何在 Eclipse 中用阿拉伯语读写

    我在 eclipse 中编写了这段代码来获取一些阿拉伯语单词 然后打印它们 public class getString public static void main String args throws Exception PrintS
  • 如何打印整个字符串池?

    我想打印包含文字的整个字符串池String使用添加的对象intern 就在垃圾收集之前 JDK有没有隐式的方法来进行这样的操作 我们如何检查字符串池 EDIT The comment suggests that there may be a
  • 有没有好的方法来解析用户代理字符串?

    我有一个Java接收模块User Agent来自最终用户浏览器的字符串的行为需要略有不同 具体取决于浏览器类型 浏览器版本甚至操作系统 例如 FireFox 7 0 Win7 Safari 3 2 iOS9 我明白了User Agent由于
  • Java 泛型/类型调度问题

    考虑以下程序 import java util List import java util ArrayList public class TypeTest public static class TypeTestA extends Type
  • Java:从元素创建 DOM 元素,而不是文档

    如您所知 在 Java 中创建 Dom 元素的正确方法是执行以下操作 import org w3c dom Document import org w3c dom Element Document d Element e e d creat
  • PropertySources 中各种源的优先级

    Spring引入了新的注释 PropertySources对于所有标记为的类 Configuration since 4 0 需要不同的 PropertySource作为论证 PropertySources PropertySource c
  • 使用 Java 在浏览器中下载 CSV 文件

    我正在尝试在 Web 应用程序上添加一个按钮 单击该按钮会下载一个 CSV 文件 该文件很小 大小仅约 4KB 我已经制作了按钮并附加了一个侦听器 文件也准备好了 我现在唯一需要做的就是创建单击按钮时下载 csv 文件的实际事件 假设 fi
  • 所有junit测试后的清理

    在我的项目中 我必须在所有测试之前进行一些存储库设置 这是使用一些棘手的静态规则来完成的 然而 在所有测试之后我不知道如何进行清理 我不想保留一些神奇的静态数字来引用所有测试方法的数量 我应该一直维护它 最受赞赏的方法是添加一些侦听器 该侦
  • 为什么我在 Mac 上看到“java.lang.reflect.InaccessibleObjectException: Unable to make private java.nio.DirectByteBuffer(long,int)accessibl

    我已经在工作中愉快地构建代码好几天了 但突然我的一个项目 不是全部 失败并出现此错误消息 看看下面的答案吧 我是如何修复它的 起初我用谷歌搜索 看到很多有这个问题的人正在使用 Java 16 但我认为 错误 我正在使用 Java 11 因为
  • 使用 java 按电子邮件发送日历邀请

    我正在尝试使用 java 发送每封电子邮件的日历邀请 收件人收到电子邮件 但不会显示接受或拒绝的邀请 而是将该事件自动添加到他的日历中 我正在使用 ical4j jar 构建活动 邀请 private Calendar getInvite
  • 在 Spring Context 加载实际的 Spring Bean 之前是否模拟了模拟 bean (@MockBean)?

    让我们以下面的例子为例 Autowired MockBean private Foo foobar Spring Context 是否加载类Foo首先 然后应用模拟 或者是 Mockbean以某种方式被检测到 Spring 创建并应用模拟而
  • Java:VM 如何在 32 位处理器上处理 64 位“long”

    JVM 如何在 32 位处理器上处理 64 位的原始 long 在多核 32 位机器上可以并行利用多个核心吗 64 位操作在 32 位机器上慢了多少 它可能使用多个核心来运行不同的线程 但不会并行使用它们进行 64 位计算 64 位长基本上
  • 尝试在没有 GatewayIntent 的情况下访问消息内容

    我希望每当我写一条打招呼的消息时 机器人都会在控制台中响应一条消息 但它只是给我一个错误 JDA MainWS ReadThread WARN JDA Attempting to access message content without
  • 参数动态时如何构建 JPQL 查询?

    我想知道是否有一个好的解决方案来构建基于过滤器的 JPQL 查询 我的查询太 富有表现力 我无法使用 Criteria 就像是 query Select from Ent if parameter null query WHERE fiel
  • 为什么 ConcurrentHashMap::putIfAbsent 比 ConcurrentHashMap::computeIfAbsent 更快?

    使用 ConcurrentHashMap 我发现computeIfAbsent 比putIfAbsent 慢两倍 这是简单的测试 import java util ArrayList import java util List import
  • 让JScrollPane控制多个组件

    对于我的应用程序 我正在设计一个脚本编辑器 目前我有一个JPanel其中包含另一个JPanel保存行号 位于左侧 以及JTextArea用于允许用户输入代码 位于右侧 目前 我已经实施了JScrollPane on the JTextAre
  • 我想要一个 Java 阿拉伯语词干分析器

    我正在寻找阿拉伯语的 Java 词干分析器 我找到了一个名为 AraMorph 的库 但它的输出是无法控制的 并且它会形成不需要的单词 还有其他阿拉伯语词干分析器吗 这是新的阿拉伯语词干分析器 Assem 的阿拉伯语轻词干分析器 http
  • 如何将实例变量传递到 Quartz 作业中?

    我想知道如何在 Quartz 中外部传递实例变量 下面是我想写的伪代码 如何将 externalInstance 传递到此作业中 public class SimpleJob implements Job Override public v
  • java中如何找到class文件的包

    我正在编写一个使用 class 文件的 java 程序 我希望能够读取文件系统上的 class 文件 使用 InputStream 并确定它所在的包 该 class 文件可能不在一个好的包目录结构中 它可能位于某个随机位置 我怎样才能做到这
  • 使用 eclipse IDE 配置 angularjs

    我想开始使用 AngularJs 和 Java Spring 进行开发 我使用 Eclipse 作为 IDE 我想配置我的 Eclipse 以使这些框架无缝工作 我知道我可能要求太多 但相信我 我已经做了很多研究 你们是我最后的选择 任何帮

随机推荐