C#编程之AOP编程思想

目录
  • 一、什么是AOP
  • 二、编程思想的发展路线
    • 1、POP
    • 2、OOP
    • 3、AOP
  • 三、实现AOP
    • 1、静态代理
    • 2、动态代理

一、什么是AOP

AOP:Aspect Oriented Programming的缩写,意为面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。AOP是OOP思想的延续。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

为什么要学习AOP呢?

AOP的应用场景非常广泛,在一些高级工程师或者架构师的面试过程中,频率出现的比较多。

二、编程思想的发展路线

1、POP

POP:Procedure Oriented Programming的缩写,即面向过程编程,是一种以过程为中心的编程思想。

面向过程是分析出解决问题的步骤,然后用函数或者方法,把这些步骤一步一步的实现,使用的时候在一个一个的一次调用函数或者方法,这就是面向过程编程。最开始的时候都是面向过程编程。面向过程是最为实际的一种思考方式。就算是面向对象编程,里面也是包含有面向过程的编程思想,因为面向过程是一种基础的编程思考方式,它从实际出发来考虑如何实现需求。

POP的不足:面向过程编程,只能处理一些简单的问题,无法处理一些复杂的问题。如果问题很复杂,全部以流程来思考的话,会发现流程很混乱,甚至流程都不能进行下去。

2、OOP

OOP:Object Oriented Programming的缩写,即面向对象编程。

早期的计算机编程都是面向过程的,因为早期的编程都比较简单。但是随着时间的发展,需求处理的问题越来越多,问题就会越来越复杂,这时就不能简单的使用面向过程的编程了,就出现了面向对象编程。在计算机里面,把所有的东西都想象成一种事物。现实世界中的对象都有一些属性和行为,也就对应计算机中的属性和方法。

面向对象编程就是把构成问题的事物分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描述某个事物在整个解决问题的步骤中的行为。

我们以一栋大楼为例来说明OOP的不足。

我们把系统比喻成一栋楼,类或者对象是砖块,砖块组成了一面墙,多面墙构成一间房间,多个房间构成一栋楼。
这就好比一个模块的功能是由多个类实现,模块又组成了某一项服务,多个服务构成了一个完整的系统。一个系统开发完成并不代表就真的完成了,以后肯定会有各种需求的变更出现,需求变更出现以后就要去修改代码,代码都在类里面,这就相当于去修改类。如果是小范围的修改影响还不是很大,如果是大范围的修改,影响就比较大了。即使每次修改都很小,但是如果经常进行修改,影响也会很大。就会造成系统的不稳定。我们得出结论:类应该是固定的,不应该频繁的去修改,甚至是不允许修改。这也是为什么有那么多的设计原则和设计模式。大部分的设计模式都是为了解决这类问题的,即在不修改类的前提下去扩展功能。

OOP的不足:产生新的需求会导致程序代码不断的进行修改,容易造成程序的不稳定。

如果非常了解OOP的话,那么我们应该知道,从对象的组织角度来讲,分类方法都是以继承关系为主线的,我们称为纵向。如果只使用OOP思想的话,会带来两个问题:
1、共性问题。
2、扩展问题,需要对先有类进行扩展时就比较困难了。

OOP与POP的区别:

在对比面向过程的时候,面向对象的方法是把事物最小化为对象,包括属性和方法。当程序的规模比较小的时候,面向过程编程还是有一些优势的,因为这时候程序的流程是比较容易梳理清楚的。以早上去上班为例,过程就是起床、穿衣、刷牙洗脸、去公司。每一步都是按照顺序完成的,我们只需要按照步骤去一步一步的实现里面的方法就行了,最后在依次调用实现的方法即可,这就是面向过程开发。

如果使用面向对象编程,我们就需要抽象出来一个员工类,该员工具有起床、穿衣、刷牙洗脸、去公司的四个方法。但是,最终要实现早上去上班的这个需求的话,还是要按照顺序依次来调用四个方法。最开始的时候,我们是按照面向过程的思想来思考该需求,然后在按照面向对象的思想来抽象出几个方法,最终要实现这个需求,还是要按照面向过程的顺序来实现。

面向对象和面向过程的区别仅仅是在思考问题方式上面的不同。最终你会发现,在你实现这个需求的时候,即使使用了面向对象的思想抽象出来了员工类,但是最后还是要使用面向过程来实现这个需求。

3、AOP

AOP:Aspect Oriented Programming的缩写,即面向切面编程。是对OOP的一种补充,在不修改原始类的情况下,给程序动态添加统一功能的一种技术。

OOP关注的是将需求功能划分为不同的并且相对独立、封装良好的类,依靠继承和多态来定义彼此的关系。AOP能够将通用需求功能从不相关的类中分离出来,很多类共享一个行为,一旦发生变化,不需要去修改很多类,只需要去修改这一个类即可。

AOP中的切面是指什么呢?切面指的是横切关注点。看下面一张图:

OOP是为了将状态和行为进行模块化。上图是一个商场系统,我们使用OOP将该系统纵向分为订单管理、商品管理、库存管理模块。在该系统里面,我们要进行授权验证。像订单、商品、库存都是业务逻辑功能,但是这三个模块都需要一些共有的功能,比如说授权验证、日志记录等。我们不可能在每个模块里面都去写授权验证,而且授权验证也不属于具体的业务,它其实属于功能性模块,并且会横跨多个业务模块。可以看到这里是横向的,这就是所谓的切面。通俗的将,AOP就是将公用的功能给提取出来,如果以后这些公用的功能发生了变化,我们只需要修改这些公用功能的代码即可,其它的地方就不需要去更改了。所谓的切面,就是只关注通用功能,而不关注业务逻辑,而且不修改原有的类。

AOP优势:

  • 将通用功能从业务逻辑中抽离出来,提高代码复用性,有利于后期的维护和扩展。
  • 软件设计时,抽出通用功能(切面),有利于软件设计的模块化,降低软件架构的复杂度。

AOP的劣势:

  • AOP的对OOP思想的一种补充,它无法单独存在。如果说单独使用AOP去设计一套系统是不可能的。在设计系统的时候,如果系统比较简单,那么可以只使用POP或者OOP来设计。如果系统很复杂,就需要使用AOP思想。首先要使用POP来梳理整个业务流程,然后根据POP的流程,去整理类和模块,最后在使用AOP来抽取通用功能。

AOP和OOP的区别:

  • 面向目标不同:OOP是面向名词领域(抽象出来一个事物,比如学生、员工,这些都是名词)。AOP是面向动词领域(比如鉴权、记录日志,这些都是动作或行为)。
  • 思想结构不同:OOP是纵向的(以继承为主线,所以是纵向的)。AOP是横向的。
  • 注重方面不同:OOP是注重业务逻辑单元的划分,AOP偏重业务处理过程中的某个步骤或阶段。

POP、OOP、AOP三种思想是相互补充的。在一个系统的开发过程中,这三种编程思想是不可或缺的。

三、实现AOP

我们在上面讲解了有关AOP的一些理论知识,那么如何在代码里面实现呢?

实现AOP有两种方式:

  • 静态代理实现。所谓静态代理,就是我们自己来写代理对象。
  • 动态代理实现。所谓动态代理,就是在程序运行时,去生成一个代理对象。

1、静态代理

实现静态代理需要使用到两种设计模式:装饰器模式和代理模式。

装饰器模式:允许向一个现有的对象添加新的功能,同时又不改变这个现有对象的结构。属于结构型设计模式,它是作为现有类的一种包装。首先会创建一个装饰类,用来包装原有的类,并在保持类的完整性的前提下,提供额外的功能。看下面的例子。

我们首先创建一个User类:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace StaticDemo.Model
{
    public class User
    {
        public string Name { get; set; }
        public string Password { get; set; }
    }
}

接着我们创建一个账号服务的接口,里面有一个方法,用来注册一个用户:

using StaticDemo.Model;

namespace StaticDemo.Services
{
    /// <summary>
    /// 接口
    /// </summary>
    public interface IAccountService
    {
        /// <summary>
        /// 注册用户
        /// </summary>
        /// <param name="user"></param>
        void Reg(User user);
    }
}

然后创建一个类来实现上面的接口:

using StaticDemo.Model;
using System;

namespace StaticDemo.Services
{
    /// <summary>
    /// 实现IAccountService接口
    /// </summary>
    public class AccountService : IAccountService
    {
        public void Reg(User user)
        {
            // 业务代码 之前 或者之后执行一些其它的逻辑
            Console.WriteLine($"{user.Name}注册成功");
        }
    }
}

我们在创建一个装饰器类:

using StaticDemo.Model;
using StaticDemo.Services;
using System;

namespace StaticDemo
{
    /// <summary>
    /// 装饰器类
    /// </summary>
    public class AccountDecorator : IAccountService
    {
        private readonly IAccountService _accountService;

        public AccountDecorator(IAccountService accountService)
        {
            _accountService = accountService;
        }

        public void Reg(User user)
        {
            Before();
            // 这里调用注册的方法,原有类里面的逻辑不会改变
            // 在逻辑前面和后面分别添加其他逻辑
            _accountService.Reg(user);
            After();
        }

        private void Before()
        {
            Console.WriteLine("注册之前的逻辑");
        }

        private void After()
        {
            Console.WriteLine("注册之后的逻辑");
        }
    }
}

我们会发现装饰器类同样实现了IAccountService接口。最后我们在Main方法里面调用:

using StaticDemo.Model;
using StaticDemo.Services;
using System;

namespace StaticDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            // 实例化对象
            IAccountService accountService = new AccountService();
            // 实例化装饰器类,并用上面的实例给构造方法传值
            var account = new AccountDecorator(accountService);
            var user = new User { Name = "Rick", Password = "12345678" };
            // 调用装饰器类的注册方法,相当于调用实例化对象的注册方法
            account.Reg(user);

            Console.ReadKey();
        }
    }
}

运行结果:

下面我们在来看看如何使用代理模式实现。

代理模式:即一个类代表另一个类的功能。我们会创建一个代理类,这个代理类和装饰器类基本一样。看一下代码:

using StaticDemo.Model;
using StaticDemo.Services;
using System;

namespace StaticDemo
{
    /// <summary>
    /// 代理类
    /// </summary>
    public class ProxyAccount : IAccountService
    {
        private readonly IAccountService _accountService;

        /// <summary>
        /// 构造函数没有参数
        /// 直接在里面创建了AccountService类
        /// </summary>
        public ProxyAccount()
        {
            _accountService = new AccountService();
        }

        public void Reg(User user)
        {
            before();
            _accountService.Reg(user);
            after();
        }

        private void before()
        {
            Console.WriteLine("代理:注册之前的逻辑");
        }

        private void after()
        {
            Console.WriteLine("代理:注册之后的逻辑");
        }
    }
}

Main方法里面调用:

using StaticDemo.Model;
using StaticDemo.Services;
using System;

namespace StaticDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            #region 装饰器模式
            //// 实例化对象
            //IAccountService accountService = new AccountService();
            //// 实例化装饰器类,并用上面的实例给构造方法传值
            //var account = new AccountDecorator(accountService);
            //var user = new User { Name = "Rick", Password = "12345678" };
            //// 调用装饰器类的注册方法,相当于调用实例化对象的注册方法
            //account.Reg(user);
            #endregion

            #region 代理模式
            var account = new ProxyAccount();
            var user = new User { Name = "Tom", Password = "12345678" };
            account.Reg(user);
            #endregion

            Console.ReadKey();
        }
    }
}

运行结果:

可能有的人会发现,装饰器类和代理类很相像,功能也一模一样,仅仅是构造函数不同。那么装饰器模式和代理模式有区别吗?有些东西,形式上看起来区别很小,但实际上他们区别很大。它们在形式上确实一样,不管是装饰器类还是代理类,它们都要实现相同的接口,但是它们在运用的时候还是有区别的。

装饰器模式关注于在一个对象上动态添加方法,而代理模式关注于控制对象的访问。简单来说,使用代理模式,我们的代理类可以隐藏一个类的具体信息。var account = new ProxyAccount();仅看这段代码不看源码,不知道里面代理的是谁。

当使用代理模式的时候,我们常常是在代理类中去创建一个对象的实例:_accountService = new AccountService()。而当我们使用装饰器模式的时候,我们通常是将原始对象作为一个参数传递给装饰器的构造函数。简单来说,在使用装饰器模式的时候,我们可以明确地知道装饰的是谁,而且更重要的是,代理类里面是写死的,在编译的时候就确定了关系。而装饰器是在运行时来确定的。

2、动态代理

动态代理实现也有两种方式;

  • 通过代码织入的方式。例如PostSharp第三方插件。我们知道.NET程序最终会编译成IL中间语言,在编译程序的时候,PostSharp会动态的去修改IL,在IL里面添加代码,这就是代码织入的方式。
  • 通过反射的方式实现。通过反射实现的方法非常多,也有很多实现了AOP的框架,例如Unity、MVC过滤器、Autofac等。

我们先来看看如何使用PostSharp实现动态代理。PostSharp是一款收费的第三方插件。

首先新创建一个控制台应用程序,然后创建一个订单业务类:

using System;

namespace PostSharpDemo
{
    /// <summary>
    /// 订单业务类
    /// </summary>
    public class OrderBusiness
    {
        public void DoWork()
        {
            Console.WriteLine("执行订单业务");
        }
    }
}

接着在Main方法里面调用:

using System;

namespace PostSharpDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            OrderBusiness order = new OrderBusiness();
            // 调用方法
            order.DoWork();
            Console.ReadKey();
        }
    }
}

运行结果:

这时又提出了一个新的需求,要去添加一个日志功能,记录业务的执行情况,按照以前的办法,需要定义一个日志帮助类:

using System;
using System.IO;

namespace PostSharpDemo
{
    public class LgoHelper
    {
        public static void RecoreLog(string message)
        {
            string strPath = AppDomain.CurrentDomain.BaseDirectory+"\\log.txt";
            using(StreamWriter sw=new StreamWriter(strPath,true))
            {
                sw.WriteLine(message);
                sw.Close();
            }
        }
    }
}

如果不使用AOP,我们就需要在记录日志的地方实例化Loghelper对象,然后记录日志:

using System;

namespace PostSharpDemo
{
    /// <summary>
    /// 订单业务类
    /// </summary>
    public class OrderBusiness
    {
        public void DoWork()
        {
            // 记录日志
            LgoHelper.RecoreLog("执行业务前");
            Console.WriteLine("执行订单业务");
            LgoHelper.RecoreLog("执行业务后");
        }
    }
}

我们再次运行程序,查看结果:

我们看看日志内容:

这样修改可以实现记录日志的功能。但是上面的方法会修改原先已有的代码,这就违反了开闭原则。而且添加日志也不是业务需求的变动,不应该去修改业务代码。下面使用AOP来实现。首先安装PostSharp,直接在NuGet里面搜索,然后安装即可:

然后定义一个LogAttribute类,继承自OnMethodBoundaryAspect。这个Aspect提供了进入、退出函数等连接点方法。另外,Aspect上必须设置“[Serializable] ”,这与PostSharp内部对Aspect的生命周期管理有关:

using PostSharp.Aspects;
using System;

namespace PostSharpDemo
{
    [Serializable]
    [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
    public class LogAttribute: OnMethodBoundaryAspect
    {
        public string ActionName { get; set; }
        public override void OnEntry(MethodExecutionArgs eventArgs)
        {
            LgoHelper.RecoreLog(ActionName + "开始执行业务前");
        }

        public override void OnExit(MethodExecutionArgs eventArgs)
        {
            LgoHelper.RecoreLog(ActionName + "业务执行完成后");
        }
    }
}

然后Log特性应用到DoWork函数上面:

using System;

namespace PostSharpDemo
{
    /// <summary>
    /// 订单业务类
    /// </summary>
    public class OrderBusiness
    {
        [Log(ActionName ="DoWork")]
        public void DoWork()
        {
            // 记录日志
            // LgoHelper.RecoreLog("执行业务前");
            Console.WriteLine("执行订单业务");
            // LgoHelper.RecoreLog("执行业务后");
        }
    }
}

这样修改以后,只需要在方法上面添加一个特性,以前记录日志的代码就可以注释掉了,这样就不会再修改业务逻辑代码了,运行程序:

在看看日志:

这样就实现了AOP功能。

我们在看看使用Remoting来实现动态代理。

首先还是创建一个User实体类:

namespace DynamicProxy.Model
{
    public class User
    {
        public string Name { get; set; }
        public string Password { get; set; }
    }
}

然后创建一个接口,里面有一个注册方法:

using DynamicProxy.Model;

namespace DynamicProxy.Services
{
    public interface IAccountService
    {
        void Reg(User user);
    }
}

然后创建接口的实现类:

using DynamicProxy.Model;
using System;

namespace DynamicProxy.Services
{
    public class AccountService : MarshalByRefObject, IAccountService
    {
        public void Reg(User user)
        {
            Console.WriteLine($"{user.Name}注册成功");
        }
    }
}

然后创建一个泛型的动态代理类:

using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Messaging;
using System.Runtime.Remoting.Proxies;

namespace DynamicProxy
{
    public class DynamicProxy<T> : RealProxy
    {
        private readonly T _target;

        // 执行之前
        public Action BeforeAction { get; set; }

        // 执行之后
        public Action AfterAction { get; set; }

        // 被代理泛型类
        public DynamicProxy(T target) : base(typeof(T))
        {
            _target = target;
        }

        // 代理类调用方法
        public override IMessage Invoke(IMessage msg)
        {
            var reqMsg = msg as IMethodCallMessage;
            var target = _target as MarshalByRefObject;

            BeforeAction();
            // 这里才真正去执行代理类里面的方法
            // target表示被代理的对象,reqMsg表示要执行的方法
            var result = RemotingServices.ExecuteMessage(target, reqMsg);
            AfterAction();
            return result;
        }

    }
}

我们看到,这个泛型动态代理类里面有两个泛型委托:BeforeAction、AfterAction。通过构造函数把代理泛型类传递进去。最后调用Invoke方法执行代理类的方法。

最后我们还要创建一个代理工厂类,用来创建代理对象,通过调用动态代理来创建动态代理对象:

using System;

namespace DynamicProxy
{
    /// <summary>
    /// 动态代理工厂类
    /// </summary>
    public static class ProxyFactory
    {
        public static T Create<T>(Action before, Action after)
        {
            // 实例化被代理泛型对象
            T instance = Activator.CreateInstance<T>();
            // 实例化动态代理,创建动态代理对象
            var proxy = new DynamicProxy<T>(instance) { BeforeAction = before, AfterAction = after };
            // 返回透明代理对象
            return (T)proxy.GetTransparentProxy();
        }
    }
}

我们最后在Main方法里面调用:

using DynamicProxy.Model;
using DynamicProxy.Services;
using System;

namespace DynamicProxy
{
    class Program
    {
        static void Main(string[] args)
        {
            // 调用动态代理工厂类创建动态代理对象,传递AccountService,并且传递两个委托
            var acount = ProxyFactory.Create<AccountService>(before:() =>
            {
                Console.WriteLine("注册之前");
            }, after:() =>
            {
                Console.WriteLine("注册之后");
            });

            User user = new User()
            {
             Name="张三",
             Password="123456"
            };
            // 调用注册方法
            acount.Reg(user);

            Console.ReadKey();
        }
    }
}

程序运行结果:

这样就利用Remoting实现了动态代理。

GitHub地址:https://github.com/jxl1024/AOP

到此这篇关于C#编程之AOP编程思想的文章就介绍到这了。希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • 利用C#实现AOP常见的几种方法详解

    前言 AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的中统一处理业务逻辑的一种技术,比较常见的场景是:日志记录,错误捕获.性能监控等 AOP的本质是通过代理对象来间接执行真实对象,在代理类中往往会添加装饰一些额外的业务代码,比如如下代码: class RealA { public virtual string Pro { get; set; } public virtual void ShowHello(str

  • C# 使用 Castle 实现 AOP及如何用 Autofac 集成 Castle

    Castle 是 2003 年诞生于 Apache Avalon 项目,目的是为了创建一个IOC 框架.发展到现在已经有四个组件: ORM组件:ActiveRecord IOC组件:Windsor 动态代理组件:DynamicProxy Web MVC组件:MonoRail 本文主要介绍 动态代理组件 Castle.DynamicProxy 基本用法 Castle.DynamicProxy 是通过 Emit 反射动态生成代理类来实现的,效率相对静态植入要慢一点,但比普通的反射又高一些.动态代理只

  • C#开源的AOP框架--KingAOP基础

    AOP面向切面编程(Aspect Oriented Programming),是通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术.Spring框架用的核心技术就是AOP,是函数式编程的一种衍生范型.利用AOP的好处就是可以对业务逻辑进行隔离,降低耦合度,提高程序的可重用性,同时提高了开发的效率.开源的AOP也有不少,我这里用的KingAOP. 1 项目结构 2 定义一个日志记录的实体类User和LoggingAspect切面日志类 namespace AOPDemo.Logging

  • 浅谈C# AOP的简单实现

    前言:为了弄清楚AOP,博主也是拼了.这篇打算写写AOP,说起AOP,其实博主接触这个概念也才几个月,了解后才知道,原来之前自己写的好多代码原理就是基于AOP的,比如MVC的过滤器Filter,它里面的异常捕捉可以通过FilterAttribute,IExceptionFilter去处理,这两个对象的处理机制内部原理应该就是AOP,只不过之前没有这个概念罢了. 一.AOP概念 老规矩,还是先看官方解释:AOP(Aspect-Oriented Programming,面向切面的编程),它是可以通过

  • C#编程之AOP编程思想

    目录 一.什么是AOP 二.编程思想的发展路线 1.POP 2.OOP 3.AOP 三.实现AOP 1.静态代理 2.动态代理 一.什么是AOP AOP:Aspect Oriented Programming的缩写,意为面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术.AOP是OOP思想的延续.利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率. 为什么要学习AOP呢? AOP的应用场景非常广

  • C#网络编程之Socket编程

    目录 一:什么是SOCKET 套接字分类 二:SOCKET相关概念 1.端口 2.协议 2.1 TCP: 2.2 UDP 三:socket一般应用模式: 四:SOCKET通信基本流程图: 服务器端: 客户端: 五:示例程序 一:什么是SOCKET socket的英文原义是“孔”或“插座”.作为进程通信机制,取后一种意思.通常也称作“套接字”,用于描述IP地址和端口,是一个通信链的句柄(其实就是两个程序通信用的).socket非常类似于电话插座.以一个电话网为例:电话的通话双方相当于相互通信的2个

  • 深入学习C#网络编程之HTTP应用编程(上)

    我们学习网络编程最熟悉的莫过于Http,好,我们就从Http入手,首先我们肯定要了解一下http的基本原理和作为,对http的工作原理有 一定程度的掌握,对我们下面的学习都是有很大帮助的. 一: 工作方式 ①:client和server建立可靠的TCP连接. ②:然后client通过Socket向server发送http请求. ③:server端处理请求,返回处理数据. ④:在http1.0中,client与server之间的tcp连接立即断开. 但在http1.1中,因为默认支持"tcp的长连

  • 深入学习C#网络编程之HTTP应用编程(下)

    第三篇来的好晚啊,上一篇说了如何向服务器推送信息,这一篇我们看看如何"快好准"的从服务器下拉信息. 网络上有很多大资源文件,比如供人下载的zip包,电影(你懂的),那么我们如何快速的进行下载,大家第一反应肯定就是多线程下载, 那么这些东西是如何做的呢?首先我们可以从"QQ的中转站里面拉一个rar下来". 然后用fiddler监视一下,我们会发现一个有趣的现象: 第一:7.62*1024*1024≈7990914  千真万确是此文件 第二:我明明是一个http链接,t

  • Spring AOP详解面向切面编程思想

    目录 1. 什么是 Spring AOP 2. AOP 的组成 2.1 切面 (Aspect) 2.2 切点 (Pointcur) 2.3 连接点 (Join Point) 2.4 通知 (Advice) 3. Spring AOP 的使用 3.1 添加 AOP 框架 3.2 定义切面和切点 3.3 定义通知 (五种) 4. Spring AOP 实现原理 4.1 织入 (Weaving) 4.2 JDK 和 CGLIB 实现的区别 1. 什么是 Spring AOP AOP (Aspect O

  • Linux编程之ICMP洪水攻击

    我的上一篇文章<Linux编程之PING的实现>里使用ICMP协议实现了PING的程序,ICMP除了实现这么一个PING程序,还有哪些不为人知或者好玩的用途?这里我将介绍ICMP另一个很有名的黑科技:ICMP洪水攻击. ICMP洪水攻击属于大名鼎鼎的DOS(Denial of Service)攻击的一种,一种是黑客们喜欢的攻击手段,这里本着加深自己对ICMP的理解的目的,也试着基于ICMP写一段ICMP的洪水攻击小程序. 洪水攻击(FLOOD ATTACK)指的是利用计算机网络技术向目的主机发

  • java编程之AC自动机工作原理与实现代码

    在阅读本文之前,大家可以先参考下<多模字符串匹配算法原理及Java实现代码> 简介: 本文是博主自身对AC自动机的原理的一些理解和看法,主要以举例的方式讲解,同时又配以相应的图片.代码实现部分也予以明确的注释,希望给大家不一样的感受.AC自动机主要用于多模式字符串的匹配,本质上是KMP算法的树形扩展.这篇文章主要介绍AC自动机的工作原理,并在此基础上用Java代码实现一个简易的AC自动机. 1.应用场景-多模字符串匹配 我们现在考虑这样一个问题,在一个文本串text中,我们想找出多个目标字符串

  • java编程之xpath介绍

    一.使用dom4j支持XPATH的操作 -可以直接获取到某个元素,而不用一层一层的解析获取 XPATH如何使用: 第一种形式:/AAA/BBB/CCC,一个/代表一层,表示获取到AAA下面的BBB下面的CCC 第二种形式://BBB,表示和这个名称相同的都可以得到,只要名称是BBB都可以得到.//DDD/BBB:得到所有DDD下面的所有的BBB 第三种形式:/AAA/BBB/CCC/*,得到所有AAA下面BBB下面CCC下面的所有的元素./*/*/*/BBB,表示限制前三层,前三层无论是什么名称

  • 深入分析Java并发编程之CAS

    在Java并发编程的世界里,synchronized 和 Lock 是控制多线程并发环境下对共享资源同步访问的两大手段.其中 Lock 是 JDK 层面的锁机制,是轻量级锁,底层使用大量的自旋+CAS操作实现的. 学习并发推荐<Java并发编程的艺术> 那什么是CAS呢?CAS,compare and swap,即比较并交换,什么是比较并交换呢?在Lock锁的理念中,采用的是一种乐观锁的形式,即多线程去修改共享资源时,不是在修改之前就加锁,而是乐观的认为没有别的线程和自己争锁,就是通过CAS的

  • 分析并发编程之LongAdder原理

    目录 一.前言 二.LongAdder类的使用 三.LongAdder原理的直观理解 四.源码分析 五.与AtomicInteger的比较 六.思想的抽象 一.前言 ConcurrentHashMap的源码采用了一种比较独特的方式对map中的元素数量进行统计,自然是要好好研究一下其原理思想,同时也能更好地理解ConcurrentHashMap本身. 本文主要思路分为以下5个部分: 1.计数的使用效果 2.原理的直观图解 3.源码的细节分析 4.与AtomicInteger的比较 5.思想的抽象

随机推荐