AOP系列(一)——ProxyFactoryObject 显式创建AOP代理

2024-05-25 10:48

本文主要是介绍AOP系列(一)——ProxyFactoryObject 显式创建AOP代理,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

AOP概念

  Aspect Oriented Programming,面向切面编程,可以通过预编译方式和运行期动态代理,实现在不修改源代码的情况下给程序动态统一添加功能的一种技术。

前提


  • 了解Spring.NET IOC
  • 熟悉代理模式

  下面我们结合一个具体的例子来了解AOP。

基本情景

这里写图片描述

User类

    /// <summary>/// 用户实体,具有姓名和年龄两个属性/// </summary>public class User{public string Name { get; set; }public int Age { get; set; }}

IUserService

    public interface IUserService{//获得用户信息void GetUserInfo(User enUser);}

UserService

    public class UserService:IUserService{/// <summary>/// 获得用户的信息/// </summary>/// <param name="enUser">用户实体</param>public void GetUserInfo(User enUser){//输出用户的姓名和年龄Console.WriteLine("姓名:"+enUser .Name+"年龄:"+enUser .Age  );}}

客户端(控制台应用程序)Program

  • “ new()”出具体的实现——这里我们不采用此方式
    class Program{static void Main(string[] args){//实例化一个实体User enUser = new User(){Name = "Danny",Age = 15};           IUserService userService = new UserService();userService.GetUserInfo(enUser);}}
  • 通过Spring IOC获得具体实现(相当于工厂)
//引入Spring.Core.dll
using Spring.Context;
using Spring.Context.Support;namespace WithoutAOP
{class Program{static void Main(string[] args){//实例化一个实体User enUser = new User(){Name = "Danny",Age = 15};          //获得Spring.IOC容器的上下文IApplicationContext context = ContextRegistry.GetContext();//根据配置文件中的配置获得业务实现类IUserService userService = (IUserService)context.GetObject("userService");//调用业务实现类的方法userService.GetUserInfo(enUser);}}
}

配置文件

    <!--Spring配置--><configSections><sectionGroup name="spring"><section name="context" type="Spring.Context.Support.ContextHandler, Spring.Core"/><section name="objects" type="Spring.Context.Support.DefaultSectionHandler, Spring.Core"/></sectionGroup></configSections><spring><context><resource uri="config://spring/objects"/></context><objects xmlns="http://www.springframework.net"><object id="userService" type="AOPExample.UserService,AOPExample"/></objects></spring>

  现在我们要为已有的业务逻辑增加日志功能。接下来看看AOP如何来实现。
  在了解之前,我们先来了解AOP中的一些术语。

AOP术语

这里写图片描述

  • 目标对象(Target),即我们要代理的对象(UserService),也就是我们要为此对象增加日志功能。
  • 关注点(Concern):如日志功能。日志功能是系统级别的,不可能只在一个对象中增加日志功能。
  • 通知(Advice):在Advice中写日志功能的具体实现。通知类实现不同的接口,如:Before,After……这些决定了日志功能如何添加(切入)到业务逻辑中,是在业务逻辑执行前添加,还是执行后添加。

AOP实现思路

  • 写具体的通知类Advice(实现日志功能)
  • 在配置文件中进行配置

    • 配置生成代理类的方式
    • 配置目标对象(可以直接配置具体的目标对象,也可以通过名称或正则表达式,程序执行后会在容器中寻找到符合条件的对象作为目标对象)

    • 配置通知类

ProxyFactoryObject 显式创建AOP代理

Advice通知类

//引入System.Aop.dll;
using Spring.Aop;       //AOP
using System.Reflection;//反射
namespace AOPExample
{/// <summary>/// Advice通知类:实现日志功能/// </summary>public class LogBeforeAdvice:IMethodBeforeAdvice{/// <summary>/// 实现接口IMethodBeforeAdvice中的Before方法,在目标方法执行前执行Before()/// </summary>/// <param name="method">拦截的方法</param>/// <param name="args">方法的参数</param>/// <param name="target">拦截的对象</param>public void Before(MethodInfo method, object[] args, object target){Console.WriteLine("拦截的方法名—>" + method.Name);Console.WriteLine("目标对象—>" + target);Console.WriteLine("参数—>");//如果参数不为空,遍历所有参数并输出if (args != null){foreach (object arg in args){Console.WriteLine("\t: " + arg);}}  }}
}

配置文件

<?xml version="1.0"?>
<configuration><!--Spring.Context.Support.ContextRegistry 的类型初始值设定项引发异常。--><!--注释掉此配置节,否则会报上述异常--><!--<startup> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.1" /></startup>-->  <!--Spring配置--><configSections><sectionGroup name="spring"><section name="context" type="Spring.Context.Support.ContextHandler, Spring.Core"/><section name="objects" type="Spring.Context.Support.DefaultSectionHandler, Spring.Core"/></sectionGroup></configSections><spring><context><resource uri="config://spring/objects"/></context><objects xmlns="http://www.springframework.net"><!--配置通知类LogBeforeAdvice--><object id="beforeAdvice" type="AOPExample.LogBeforeAdvice,AOPExample"/>         <!--通过ProxyFactoryObject 显式创建AOP代理--><object id="userServiceProxy" type="Spring.Aop.Framework.ProxyFactoryObject"><!--指定代理的真实对象--><property name="Target"><object type="AOPExample.UserService,AOPExample"/></property><!--指定具体通知类--><property name="InterceptorNames"><list><!--指定具体通知类,和前面配置的id一致--><value>beforeAdvice</value></list></property></object></objects></spring>
</configuration>

客户端

    class Program{static void Main(string[] args){//实例化用户User enUser = new User(){Name ="Jenny",Age=15};//获得Spring容器上下文IApplicationContext context = ContextRegistry.GetContext();//从配置文件获得由ProxyFactoryObject生成的代理类//需要修改客户端,原来是直接调用真实对象,现在是调用代理IUserService userServiceProxy = (IUserService)context["userServiceProxy"];userServiceProxy.GetUserInfo(enUser);}}

运行结果
这里写图片描述

总结

  • 优点:通过ProxyFactoryObject 创建代理类,省去自己手动创建代理类;
  • 缺点1:如果有多个目标对象,每个都需要在配置文件中配置;
  • 缺点2:客户端调用时,由原来调用目标对象,变成调用代理对象,需要修改客户端代码。

这篇关于AOP系列(一)——ProxyFactoryObject 显式创建AOP代理的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1001289

相关文章

Springboot如何正确使用AOP问题

《Springboot如何正确使用AOP问题》:本文主要介绍Springboot如何正确使用AOP问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录​一、AOP概念二、切点表达式​execution表达式案例三、AOP通知四、springboot中使用AOP导出

深度解析Spring AOP @Aspect 原理、实战与最佳实践教程

《深度解析SpringAOP@Aspect原理、实战与最佳实践教程》文章系统讲解了SpringAOP核心概念、实现方式及原理,涵盖横切关注点分离、代理机制(JDK/CGLIB)、切入点类型、性能... 目录1. @ASPect 核心概念1.1 AOP 编程范式1.2 @Aspect 关键特性2. 完整代码实

python如何创建等差数列

《python如何创建等差数列》:本文主要介绍python如何创建等差数列的问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录python创建等差数列例题运行代码回车输出结果总结python创建等差数列import numpy as np x=int(in

怎么用idea创建一个SpringBoot项目

《怎么用idea创建一个SpringBoot项目》本文介绍了在IDEA中创建SpringBoot项目的步骤,包括环境准备(JDK1.8+、Maven3.2.5+)、使用SpringInitializr... 目录如何在idea中创建一个SpringBoot项目环境准备1.1打开IDEA,点击New新建一个项

如何使用Maven创建web目录结构

《如何使用Maven创建web目录结构》:本文主要介绍如何使用Maven创建web目录结构的问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录创建web工程第一步第二步第三步第四步第五步第六步第七步总结创建web工程第一步js通过Maven骨架创pytho

MySQL 用户创建与授权最佳实践

《MySQL用户创建与授权最佳实践》在MySQL中,用户管理和权限控制是数据库安全的重要组成部分,下面详细介绍如何在MySQL中创建用户并授予适当的权限,感兴趣的朋友跟随小编一起看看吧... 目录mysql 用户创建与授权详解一、MySQL用户管理基础1. 用户账户组成2. 查看现有用户二、创建用户1. 基

Python中使用uv创建环境及原理举例详解

《Python中使用uv创建环境及原理举例详解》uv是Astral团队开发的高性能Python工具,整合包管理、虚拟环境、Python版本控制等功能,:本文主要介绍Python中使用uv创建环境及... 目录一、uv工具简介核心特点:二、安装uv1. 通过pip安装2. 通过脚本安装验证安装:配置镜像源(可

Java中实现线程的创建和启动的方法

《Java中实现线程的创建和启动的方法》在Java中,实现线程的创建和启动是两个不同但紧密相关的概念,理解为什么要启动线程(调用start()方法)而非直接调用run()方法,是掌握多线程编程的关键,... 目录1. 线程的生命周期2. start() vs run() 的本质区别3. 为什么必须通过 st

Macos创建python虚拟环境的详细步骤教学

《Macos创建python虚拟环境的详细步骤教学》在macOS上创建Python虚拟环境主要通过Python内置的venv模块实现,也可使用第三方工具如virtualenv,下面小编来和大家简单聊聊... 目录一、使用 python 内置 venv 模块(推荐)二、使用 virtualenv(兼容旧版 P

Linux lvm实例之如何创建一个专用于MySQL数据存储的LVM卷组

《Linuxlvm实例之如何创建一个专用于MySQL数据存储的LVM卷组》:本文主要介绍使用Linux创建一个专用于MySQL数据存储的LVM卷组的实例,具有很好的参考价值,希望对大家有所帮助,... 目录在Centos 7上创建卷China编程组并配置mysql数据目录1. 检查现有磁盘2. 创建物理卷3. 创