As the business gets more complex , Recently, I decided to cache some interfaces that are frequently queried but the data will not change much , This function is generally used AOP You can do it , After looking for a client, there is no ready-made one that can be used directly , A kind of , You can only develop it yourself .
Agent mode and AOP
After understanding the proxy pattern , Yes AOP It's natural to get caught , So let's start with some pre knowledge .
The proxy pattern is an example code that uses one class to control method calls from another class .
The proxy pattern has three roles :
- ISubject Interface , Responsibility is to define behavior .
- ISubject Implementation class of RealSubject, Responsibility is to achieve behavior .
- ISubject Proxy class ProxySubject, Responsibility is to control RealSubject The interview of .
There are three implementations of the proxy pattern :
- General agent .
- Compulsory agency , Coercion means not having direct access to RealSubject Methods , Must be accessed through a proxy class .
- A dynamic proxy , Dynamic means to generate proxy classes through reflection ,AOP It is generally based on dynamic proxy .
AOP There are four key knowledge points :
- The breakthrough point JoinPoint. Namely RealSubject The method of controlled access in .
- notice Advice, Is the method in the proxy class , Can control or enhance RealSubject Methods , With advance notice 、 The rear notice 、 Surround notifications, etc
- Weaving Weave, Is to call the notification and in order RealSubject Method process .
- section Aspect, Multiple entry points will form a facet .
public interface ISubject
{
void DoSomething(string value);
Task DoSomethingAsync(string value);
}
public class RealSubject : ISubject
{
public void DoSomething(string value)
{
Debug.WriteLine(value);
}
public async Task DoSomethingAsync(string value)
{
await Task.Delay(2000);
Debug.WriteLine(value);
}
}
public class Proxy : ISubject
{
private readonly ISubject _realSubject;
public Proxy()
{
_realSubject = new RealSubject();
}
/// <summary>
/// That's the entry point
/// </summary>
/// <param name="value"></param>
public void DoSomething(string value)
{
// This process is weaving in
Before();
_realSubject.DoSomething(value);
After();
}
public Task DoSomethingAsync(string value)
{
throw new NotImplementedException();
}
public void Before()
{
Debug.WriteLine(" General proxy class pre notification ");
}
public void After()
{
Debug.WriteLine(" General proxy class post notification ");
}
}
I'm using Castle.Core This library is used to implement dynamic proxy . But the asynchronous method with return value of this proxy is hard to write , however github There are already many libraries that encapsulate the implementation process , Here I use Castle.Core.AsyncInterceptor To implement an asynchronous method proxy .
public class CastleInterceptor : StandardInterceptor
{
protected override void PostProceed(IInvocation invocation)
{
Debug.WriteLine("Castle Proxy class pre notification ");
}
protected override void PreProceed(IInvocation invocation)
{
Debug.WriteLine("Castle Proxy class post notification ");
}
}
public class AsyncCastleInterceptor : AsyncInterceptorBase
{
protected override async Task InterceptAsync(IInvocation invocation, IInvocationProceedInfo proceedInfo, Func<IInvocation, IInvocationProceedInfo, Task> proceed)
{
Before();
await proceed(invocation, proceedInfo);
After();
}
protected override async Task<TResult> InterceptAsync<TResult>(IInvocation invocation, IInvocationProceedInfo proceedInfo, Func<IInvocation, IInvocationProceedInfo, Task<TResult>> proceed)
{
Before();
var result = await proceed(invocation, proceedInfo);
After();
return result;
}
public void Before()
{
Debug.WriteLine(" asynchronous Castle Proxy class pre notification ");
}
public void After()
{
Debug.WriteLine(" asynchronous Castle Proxy class post notification ");
}
}
Implement facet class and interface caching
Implementation process :
- Definition CacheAttribute Feature to mark the methods that need to be cached .
- Definition CacheInterceptor section , Implement the logic of caching data in memory .
- Using facets , Generate dynamic proxy classes for interfaces , And inject the proxy class into IOC In the container .
- Interface by IOC Get the interface implementation class to access the implementation .
The client uses Prism Of IOC To achieve inversion of control ,Prism Support for multiple IOC, I'm going to use DryIoc, Because the others IOC No more updates .
Client memory cache usage Microsoft.Extensions.Caching.Memory, This is the most commonly used .
- Definition CacheAttribute Feature to mark the methods that need to be cached .
[AttributeUsage(AttributeTargets.Method)]
public class CacheAttribute : Attribute
{
public string? CacheKey { get; }
public long Expiration { get; }
public CacheAttribute(string? cacheKey = null, long expiration = 0)
{
CacheKey = cacheKey;
Expiration = expiration;
}
public override string ToString() => $"{{ CacheKey: {CacheKey ?? "null"}, Expiration: {Expiration} }}";
}
- Definition CacheInterceptor Section class , Implement the logic of caching data in memory
public class CacheInterceptor : AsyncInterceptorBase
{
private readonly IMemoryCache _memoryCache;
public CacheInterceptor(IMemoryCache memoryCache)
{
_memoryCache = memoryCache;
}
...
// Intercept asynchronous methods
protected override async Task<TResult> InterceptAsync<TResult>(IInvocation invocation, IInvocationProceedInfo proceedInfo, Func<IInvocation, IInvocationProceedInfo, Task<TResult>> proceed)
{
var attribute = invocation.Method.GetCustomAttribute<CacheAttribute>();
if (attribute == null)
{
return await proceed(invocation, proceedInfo).ConfigureAwait(false);
}
var cacheKey = attribute.CacheKey ?? GenerateKey(invocation);
if (_memoryCache.TryGetValue(cacheKey, out TResult cacheValue))
{
if (cacheValue is string[] array)
{
Debug.WriteLine($"[Cache] Key: {cacheKey}, Value: {string.Join(',', array)}");
}
return cacheValue;
}
else
{
cacheValue = await proceed(invocation, proceedInfo).ConfigureAwait(false);
_memoryCache.Set(cacheKey, cacheValue);
return cacheValue;
}
}
// Generate cached Key
private string GenerateKey(IInvocation invocation)
{
...
}
// Format it
private string FormatArgumentString(ParameterInfo argument, object value)
{
...
}
}
- Define extension classes to generate facets , And realize chain programming , You can easily add multiple facet classes to an interface .
public static class DryIocInterceptionAsyncExtension
{
private static readonly DefaultProxyBuilder _proxyBuilder = new DefaultProxyBuilder();
// Generate section
public static void Intercept<TService, TInterceptor>(this IRegistrator registrator, object serviceKey = null)
where TInterceptor : class, IInterceptor
{
var serviceType = typeof(TService);
Type proxyType;
if (serviceType.IsInterface())
proxyType = _proxyBuilder.CreateInterfaceProxyTypeWithTargetInterface(
serviceType, ArrayTools.Empty<Type>(), ProxyGenerationOptions.Default);
else if (serviceType.IsClass())
proxyType = _proxyBuilder.CreateClassProxyTypeWithTarget(
serviceType, ArrayTools.Empty<Type>(), ProxyGenerationOptions.Default);
else
throw new ArgumentException(
$"{serviceType} Can't be intercepted , Only interfaces or classes can be intercepted ");
registrator.Register(serviceType, proxyType,
made: Made.Of(pt => pt.PublicConstructors().FindFirst(ctor => ctor.GetParameters().Length != 0),
Parameters.Of.Type<IInterceptor[]>(typeof(TInterceptor[]))),
setup: Setup.DecoratorOf(useDecorateeReuse: true, decorateeServiceKey: serviceKey));
}
// Chain programming , Easy to add multiple slices
public static IContainerRegistry InterceptAsync<TService, TInterceptor>(
this IContainerRegistry containerRegistry, object serviceKey = null)
where TInterceptor : class, IAsyncInterceptor
{
var container = containerRegistry.GetContainer();
container.Intercept<TService, AsyncInterceptor<TInterceptor>>(serviceKey);
return containerRegistry;
}
}
- Define the target interface , And mark the method
public interface ITestService
{
/// <summary>
/// An interface for querying large amounts of data
/// </summary>
/// <returns></returns>
[Cache]
Task<string[]> GetLargeData();
}
public class TestService : ITestService
{
public async Task<string[]> GetLargeData()
{
await Task.Delay(2000);
var result = new[]{" Big "," The amount "," Count "," According to the "};
Debug.WriteLine(" Query data from the interface ");
return result;
}
}
- towards IOC The container injects facet classes and business interfaces .
public partial class App
{
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
// Inject cache class
containerRegistry.RegisterSingleton<IMemoryCache>(_ => new MemoryCache(new MemoryCacheOptions()));
// Injection section class
containerRegistry.Register<AsyncInterceptor<CacheInterceptor>>();
// Inject interface and application facet classes
containerRegistry.RegisterSingleton<ITestService, TestService>()
.InterceptAsync<ITestService, CacheInterceptor>();
containerRegistry.RegisterSingleton<ITestService2, TestService2>()
.InterceptAsync<ITestService2, CacheInterceptor>();
}
...
}
effect
// AopView.xaml
<Button x:Name="cache" Content="Aop Cache interface data " />
// AopView.xaml.cs
cache.Click += (sender, args) => ContainerLocator.Container.Resolve<ITestService>().GetLargeData();
// Output
// Click Print for the first time
// Query data from the interface
// Then click Print
// [Cache] Key: PrismAop.Service.TestService2.GetLargeData(), Value: Big , The amount , Count , According to the
Last
In fact, there are many details that can be improved , For example, cache refresh rules , The server refreshes the client cache, and so on , But the client AOP The implementation of is almost like this .
I think it's helpful for you to make a recommendation or leave a message !
Source code https://github.com/yijidao/blog/tree/master/WPF/PrismAop
stay WPF Client implementation AOP And interface caching
- springboot 2.x Integrate redis,spring aop Implement interface caching
pox.xml: <dependency> <groupId>org.springframework.boot</groupId> <artifactId&g ...
- Use AOP Realization Redis Cache annotations , Support SPEL
The company's project is very important to the company Redis Use more , Because I didn't do it before AOP, So cache logic and business logic are intertwined , It is difficult to maintain, so we have recently implemented the Redis Of @Cacheable, Store the cached objects in categories redis Of Ha ...
- stay ASP.NET Core Use in AOP To simplify caching operations
Preface About the use of caching , I believe we are all familiar with each other, and we can't be familiar with each other any more , In short, the following sentence . Take data from the cache first , If you can't get it from the cache, go to the database to get it , Take it and throw it into the cache . Then we'll see code like this in the project . pu ...
- .NetCore Interface cache
1. problem : We must use the cache function when we are doing development , The general writing method is to read the cache in the required business code . Judge whether it exists . If it does not exist, read the database and set the cache . But if we have a lot of businesses that use caching , We just need ...
- ssm+redis How to use custom annotations more succinctly +AOP Realization redis cache
be based on ssm + maven + redis Use custom annotations utilize aop be based on AspectJ The way Realization redis cache How to use it more succinctly aop Realization redis cache , Don't talk much , On demo demand : Data query ...
- wpf client 【JDAgent Desktop assistant 】 Development details ( Four ) popup The control of win8.0 Of bug
Directory area : Amateur development wpf The client is finally finished .. Sun screen shot wpf client [JDAgent Desktop assistant ] Development details - The opening wpf client [JDAgent Desktop assistant ] Detailed explanation ( One ) main window Round menu ... wpf customer ...
- SpringCloud Use Feign Call other client interfaces with parameters , The incoming parameter is null Or report a mistake status 405 reading IndexService#del(Integer);
SpringCloud Use Feign Call other client interfaces with parameters , The incoming parameter is null Or report a mistake status 405 reading IndexService#del(Integer); The first method : If you ...
- Springboot Study 06-Spring AOP Encapsulation interface custom verification
Springboot Study 06-Spring AOP Encapsulation interface custom verification keyword BindingResult.Spring AOP. Custom annotation . Custom exception handling .ConstraintValidator Preface ...
- wpf client 【JDAgent Desktop assistant 】 Development details ( 3、 ... and ) Waterfall effect and UI Virtualization optimizes big data display
Directory area : Amateur development wpf The client is finally finished .. Sun screen shot wpf client [JDAgent Desktop assistant ] Development details - The opening wpf client [JDAgent Desktop assistant ] Detailed explanation ( One ) main window Round menu ... wpf customer ...
- wpf client 【JDAgent Desktop assistant 】 The amateur development is finally finished .. Sun screen shot
Directory area : Amateur development wpf The client is finally finished .. Sun screen shot wpf client [JDAgent Desktop assistant ] Development details - The opening wpf client [JDAgent Desktop assistant ] Detailed explanation ( One ) main window Round menu ... wpf customer ...
Random recommendation
- python And c Call each other
although python Development efficiency is very high , But as a scripting language , Its performance is not high , So in order to give consideration to both development efficiency and performance , Modules with high performance requirements are usually used c or c++ To implement or in c or c++ Run in python Scripts to handle logic , The former is usually python in ...
- opencart introduce TWIG template engine
1. First of all, will twig Put in bags system\library Catalog . 2. stay system/startup.php Add the introduction statement at the end of the file . require_once(DIR_SYSTEM . 'lib ...
- Access Version control of project files
Make a brief record of the use MS Access SVN( hereinafter referred to as AccessSVN) Step by step . AccessSVN stay http://accesssvn.codeplex.com/, The purpose of this product is :Access SV ...
- I want a pc Client shared with mobile phone , Just like Baidu cloud (iBarn Network disk is easy to use )
https://github.com/zhimengzhe/iBarn iBarn Net disk is a network disk based on PHP Developed advanced cloud storage system , Provide network backup of files , Synchronization and sharing services : Support breakpoint renewal , Second transmission and other functions : You can select file ...
- BZOJ_4530_[Bjoi2014] Great fusion _LCT
BZOJ_4530_[Bjoi2014] Great fusion _LCT Description Xiaoqiang will be in N Set up a communication system on an isolated planet . This communication system is the connection N A tree with a dot . The edges of the tree are added one by one . In a certain ...
- UVA11419 SAM I AM
UVA11419 SAM I AM Given a \(R\times C\) In the matrix of \(N\) A little bit , Find the minimum number of rows or columns to be selected so that each given point is covered by a row or column , Output plan \(R,\ C\leq1 ...
- HDU 6345( Substring query violence )
Each group is given a string , Output the number of substrings with the smallest dictionary order of the interval to be queried within a limited number of queries . The substring with the smallest dictionary order , Is the single character with the smallest dictionary order in the query interval , The problem is to find the minimum number of characters in the dictionary order in a section . Start blind ...
- understand HTTPS agreement
The original English text :Understanding HTTPS Protocol Recently, we have seen many sites using HTTPS The agreement provides Web services . Usually we see it on some sites containing confidential information, such as banks HTTPS agreement . Such as ...
- CSS- Pull down the navigation bar
Web There are many drop-down navigation bars in websites , Some are through CSS Realization , Some go through JavaScript Plug-in implementation , Actually CSS It's easy to implement , Let's start with a simple version of the drop-down menu : Html The code passes ul List implementation : <ul ...
- I don't Big ice 2017 new book pdf As a free download
Good intentions can dispel violence , Good will makes good fortune , Good intentions can bring karma to life , Kindness can turn around . Kindness can help people capture and build a unique sense of happiness . “ I don't ” It's kind and calm , It's also a kind of good luck , It's a kind introspection . < I don't >—— Millions of best sellers ...









