使用Autofac做类的增强

简介: 我们已经实现了用户注册功能,现在想增加日志记录功能。具体来讲就是在用户注册前后,分别输出一条日志。

我们已经实现了用户注册功能,现在想增加日志记录功能。具体来讲就是在用户注册前后,分别输出一条日志。我们当然可以修改原有的业务代码。

现在换个角度来问两个问题:
1. 团队开发中,我们很可能根本拿不到源代码,那又怎么去增加这个功能呢?
2. 这次需求是增加日志,以后再增加其他需求(比如异常处理),是不是仍然要改业务类呢?

总结一下:
我们要在不修改原有类业务代码的前提下,去做类的增强。我们的设计要符合面向对象的原则:对扩展开放,对修改封闭

都有哪些办法呢?本系列尝试以下几种方法,来实现对原有业务类的无侵入增强:


原有业务类

业务模型

namespace testAopByDecorator
{
    public class User
    {
        public string Name { get; set; }
        public int Id { get; set; }
    }
}

接口设计

namespace testAopByDecorator
{
    public interface IUserProcessor
    {
        void RegisterUser(User user);
    }
}

业务实现

using System;

namespace testAopByDecorator
{
    public class UserProcessor : IUserProcessor
    {
        public void RegisterUser(User user)
        {
            if (user == null)
            {
                return;
            }

            Console.WriteLine(string.Format("注册了一个用户{0}:{1}", user.Id, user.Name));
        }
    }
}

上层调用

using System;

namespace testAopByDecorator
{
    class Program
    {
        private static User user = new User { Id = 1, Name = "滇红" };

        static void Main(string[] args)
        {
            Register();
            Console.ReadKey();
        }

        private static void Register()
        {
            IUserProcessor processor = new UserProcessor();
            processor.RegisterUser(user);
        }
    }
}

使用Autofac做类的增强

我们将使用第三方的Autofac来对原有的类做业务增强,首先使用NuGet安装。
这里写图片描述
业务增强实现

using Castle.DynamicProxy;
using System;

namespace testAopByAutofac
{
    public class UserProcessorLog : IInterceptor
    {
        public void Intercept(IInvocation invocation)
        {
            User user = invocation.Arguments[0] as User;

            before(user);
            invocation.Proceed();
            after(user);
        }

        private void after(User user)
        {
            Console.WriteLine("注册用户后:" + user.Name);
        }

        private void before(User user)
        {
            Console.WriteLine("注册用户前:" + user.Name);
        }
    }
}

上层调用

using Autofac;
using Autofac.Extras.DynamicProxy2;
using System;

namespace testAopByAutofac
{
    class Program
    {
        private static User user = new User { Id = 1, Name = "滇红" };

        static void Main(string[] args)
        {
            RegisterAndLog();
            Console.ReadKey();
        }

        private static void RegisterAndLog()
        {
            ContainerBuilder builder = new ContainerBuilder();
            builder
                .RegisterType<UserProcessor>()
                .As<IUserProcessor>()
                .EnableInterfaceInterceptors()
                .InterceptedBy(typeof(UserProcessorLog));
            builder.RegisterType<UserProcessorLog>();

            var container =  builder.Build();

            using (var scope = container.BeginLifetimeScope())
            {
                IUserProcessor processor = (IUserProcessor)scope.Resolve<IUserProcessor>();

                processor.RegisterUser(user);
            }
        }
    }
}

对比一下扩展前后的业务展现

这里写图片描述

这里我们使用代码的方式给原有的业务类配置了拦截器(AOP依赖注入),也可以使用特性的方式。
使用特性加强业务类

using Autofac.Extras.DynamicProxy2;
using System;

namespace testAopByAutofac
{
    [Intercept(typeof(UserProcessorLog))]
    public class UserProcessor : IUserProcessor
    {
        public void RegisterUser(User user)
        {
            if (user == null)
            {
                return;
            }

            Console.WriteLine(string.Format("注册了一个用户{0}:{1}", user.Id, user.Name));
        }
    }
}

上层调用

using Autofac;
using Autofac.Extras.DynamicProxy2;
using System;

namespace testAopByAutofac
{
    class Program
    {
        private static User user = new User { Id = 1, Name = "滇红" };

        static void Main(string[] args)
        {
            Register();
            Console.WriteLine("--------------");
            RegisterAndLog();

            Console.ReadKey();
        }

        private static void RegisterAndLog()
        {
            ContainerBuilder builder = new ContainerBuilder();
            builder
                .RegisterType<UserProcessor>()
                .As<IUserProcessor>()
                .EnableInterfaceInterceptors();
                //.InterceptedBy(typeof(UserProcessorLog));//可使用特性代替
            builder.RegisterType<UserProcessorLog>();

            var container =  builder.Build();

            using (var scope = container.BeginLifetimeScope())
            {
                IUserProcessor processor = (IUserProcessor)scope.Resolve<IUserProcessor>();

                processor.RegisterUser(user);
            }
        }

        private static void Register()
        {
            IUserProcessor processor = new UserProcessor();
            processor.RegisterUser(user);
        }
    }
}

上面我们使用的是接口注入(EnableInterfaceInterceptors),也可以使用类注入(EnableClassInterceptors),此时原有业务类的方法需要显示声明为vitual虚方法。在上层调用的时候,我们就可以直接注册和解析一个类,不依赖于接口了。

相关文章
|
消息中间件 存储 NoSQL
深入Redis消息队列:Pub/Sub和Stream的对决【redis第六部分】
深入Redis消息队列:Pub/Sub和Stream的对决【redis第六部分】
629 0
|
机器学习/深度学习 异构计算 AI芯片
云端开炉,线上训练,Bert-vits2-v2.2云端线上训练和推理实践(基于GoogleColab)
对于笔者这样的穷哥们来讲,GoogleColab就是黑暗中的一道光,就算有训练时长限制,也能凑合用了,要啥自行车?要饭咱也就别嫌饭馊了,本次我们基于GoogleColab在云端训练和推理Bert-vits2-v2.2项目,复刻那黑破坏神角色莉莉丝(lilith)。
云端开炉,线上训练,Bert-vits2-v2.2云端线上训练和推理实践(基于GoogleColab)
|
6月前
|
机器学习/深度学习 人工智能 自然语言处理
TsingtaoAI亮相2025青岛西海岸科技成果对接会,以具身智能实训赋能AI人才培养
3月26日青岛——由青岛市科学技术局指导、青岛西海岸新区管委联合上海技术交易所等多家机构主办的“2025青岛西海岸新区科技成果对接会”在青岛金沙滩蓝海御华酒店盛大启幕。青岛市委常委,西海岸新区工委书记、区委书记孙永红,青岛市科学技术局副局长张栋华和上海技术交易所总裁颜明峰等参加会议并致辞。TsingtaoAI受邀参会并发表主题分享,公司负责人汶生以《基于DeepSeek的具身智能实训》为题,向与会嘉宾展示了AI具身智能技术如何突破传统边界,助力AI人才从实验室走向产业一线。
134 1
|
9月前
|
设计模式 数据库 C#
外观模式(Facade Pattern)
外观模式(Facade Pattern)是一种结构型设计模式,为子系统中的一组接口提供一个一致的接口。它通过一个高层接口简化子系统的复杂性,使客户端更容易使用。外观模式的核心角色包括外观(Facade)和子系统(Subsystems),主要优点是降低复杂性和松耦合,适用于简化接口、分层设计和遗留代码集成等场景。
120 2
|
10月前
|
Python
多进程同步之文件锁
【10月更文挑战第16天】文件锁是一种常用的多进程同步机制,它可以用于确保多个进程在访问共享资源时的互斥性。在使用文件锁时,需要注意锁的粒度、释放、竞争和性能等问题。通过合理使用文件锁,可以提高多进程程序的正确性和性能
|
Kubernetes 安全 开发工具
Kubernetes系统安全-准入控制(admission control)
文章详细介绍了Kubernetes中的准入控制机制,包括各种准入控制器的功能、如何创建和使用LimitRange和ResourceQuota资源,以及PodSecurityPolicy和准入控制器扩展的使用方法。
133 1
Kubernetes系统安全-准入控制(admission control)
|
12月前
|
Python
Python量化炒股的获取数据函数— get_billboard_list()
Python量化炒股的获取数据函数— get_billboard_list()
172 0
|
图形学 C++ C#
Unity插件开发全攻略:从零起步教你用C++扩展游戏功能,解锁Unity新玩法的详细步骤与实战技巧大公开
【8月更文挑战第31天】Unity 是一款功能强大的游戏开发引擎,支持多平台发布并拥有丰富的插件生态系统。本文介绍 Unity 插件开发基础,帮助读者从零开始编写自定义插件以扩展其功能。插件通常用 C++ 编写,通过 Mono C# 运行时调用,需在不同平台上编译。文中详细讲解了开发环境搭建、简单插件编写及在 Unity 中调用的方法,包括创建 C# 封装脚本和处理跨平台问题,助力开发者提升游戏开发效率。
1115 0
|
安全 数据安全/隐私保护
使用了代理IP之后软件或网站还是拒绝访问的原因分析
代理IP使用后仍被拒访可能因无效IP、网站反代理机制、设置错误、网络问题或软件设置不当。检查代理有效性,确认网站限制,修正设置,确保网络稳定,及调整软件代理配置是解决之道。遇到问题需针对性排查。
|
监控 前端开发 Java
Netty使用篇
Netty使用篇