// Java code usage example
//
// The @around @CheckPoint (long x) aspect does a high level (distributed)
// logging of the checkpoint
// The @CheckPointParameter annotated method parameters are logged
// as properties with the log
@CheckPoint(10)
public void annotatedCheckPointMethod(@CheckPointParameter String user) {
// -> results in @Before checkpoint logging
....code ...
}// -> results in @After checkpoint logging
// C# code usage example
//
// The [CheckPoint (long x)] dynamic proxy interceptor
// aspect does a high level (distributed) logging of the checkpoint
// The [CheckPointParameter] annotated method parameters are logged
// as properties with the log
[CheckPoint(10)]
public void AnnotatedCheckPointMethod([CheckPointParameter] String user)
{// -> results in @Before checkpoint logging
....code ...
}// -> results in @After checkpoint logging
概念:基本原则
面向切面如何工作?
在这篇文章中的实现,我们使用CTW(Compile Time Weaving)和LTW(Load Time Weaving)。
备注3:加载时间编织使用“普通” Spring AOP。“按设计的功能”(您可以称其为错误,约束或其他任何一种)之一是,切面仅适用于接口调用,因为这样您便有了com.sun代理。它不适用于实现类。结果,您需要在接口上定义切面。而且,如果您随后在纵横比高的方法内部调用另一个实现方法,则该纵横比不会执行。
注1:当您执行LTW Spring AOP时,切面类是由Spring Boot的容器加载和管理的,因此自动为您完成了布线。CTW没有这样的事情。Aspect编译器以及您的切面和Spring Boot IOC在开箱即用时效果不佳。您必须手动连接各个切面。否则,您@Autowiring将失败。
....
/**
* This is plumbing code to connect the CTW aspect to the Spring Boot IOC container
* of your app context.
* Otherwise, the CheckPointAspect is factored by the aspectj compiler,
* and then, your autowiring fails, resulting in nulls for all your @Autowired props.
* So, you need to include this method in all your CTW aspects.
* I suppose the aspectjrt checks if this method is available,
* and then uses it to factor your objects via Spring Boot?
* @return CheckPointAspect
*/
public static CheckPointAspect aspectOf() {
return SpringApplicationContextHolder.getApplicationContext().
getBean(CheckPointAspect.class);
}
...
//Helper class for your CTW/Spring Boot container wiring stuff
@Component
public class SpringApplicationContextHolder implements ApplicationContextAware {
private static ApplicationContext applicationContext = null;
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
this.applicationContext = applicationContext;
}
}
public class AOPTestImpl : AOPTest
{
// -> invocation point
// @Before is done in the interceptor below, 1. and 2.
public void DoSomething()
{
//
// invocation.Proceed() : Method block code goes below here
//
Debug.Print("3. DoSomething\n");
//
// 4. @After invocation is done in the interceptor below,
// after the invocation.Proceed(); call
//
}
public void DoAction()
{
}
}
然后,定义拦截器。
注意,在Java和.NET中,都有一些“调用点:已定义”。
public class CheckPointInterceptor : Castle.DynamicProxy.IInterceptor
{
//
// As we use PropertiesAutowired() with AutoFac,
// this object is set by the IOC container
//
public CheckPointClient checkPointClient { get; set; }
public void Intercept(Castle.DynamicProxy.IInvocation invocation)
{
Debug.Print($"1. @Before Method called {invocation.Method.Name}");
var methodAttributes = invocation.Method.GetCustomAttributes(false);
CheckPointAttribute theCheckPoint =(CheckPointAttribute)methodAttributes.Where
(a => a.GetType() == typeof(CheckPointAttribute)).SingleOrDefault();
if (theCheckPoint == null)
{
//@before intercepting code goes here
checkPointClient.CheckPoint(theCheckPoint.Id);
Debug.Print($"2. CheckPointAttribute on method found with cp id =
{theCheckPoint.Id}\n");
}
//
// This is the actual "implementation method code block".
// @Before code goes above this call
//
invocation.Proceed();
//
// Any @After method block code goes below here
//
Debug.Print($"4. @After method: {invocation.Method.Name}");
}
}
接下来,使用AutoFac注册对象:
var builder = new ContainerBuilder();
...
builder.RegisterType()
.As()
.EnableInterfaceInterceptors()
.InterceptedBy(typeof(CheckPointInterceptor))
.PropertiesAutowired()
.PreserveExistingDefaults();
...
var container = builder.Build();
...
最后,让我们测试并使用代码:
using (var scope = container.BeginLifetimeScope())
{
//
// Create the registered AOPTest object, with the interceptor in between
//
AOPTest aOPTest = scope.Resolve();
//
// Call the method, with the [CheckPoint(Id = 10)] on it
//
aOPTest.DoSomething();
}
public class CheckPointActionAtrribute : Microsoft.AspNetCore.Mvc.Filters.ActionFilterAttribute
{
//
// Your custom checkpoint Id for this CheckPoint attribute
//
public long Id { get; set; }
//
// @Before
//
public override void OnActionExecuting
(Microsoft.AspNetCore.Mvc.Filters.ActionExecutingContext context)
{
ControllerActionDescriptor actionDescriptor =
(ControllerActionDescriptor)context.ActionDescriptor;
Debug.Print($"1. @Before Method called
{actionDescriptor.ControllerName}.{actionDescriptor.ActionName}");
var controllerName = actionDescriptor.ControllerName;
var actionName = actionDescriptor.ActionName;
var parameters = actionDescriptor.Parameters;
var fullName = actionDescriptor.DisplayName;
//
// CheckPointActionAtrribute are not factored by the IOC
//
CheckPointClient checkPointClient = BootStapper.Resolve();
checkPointClient.CheckPoint(Id);
}
//
// @After
//
public override void OnActionExecuted(ActionExecutedContext context)
{
ControllerActionDescriptor actionDescriptor =
(ControllerActionDescriptor)context.ActionDescriptor;
Debug.Print($"3. @After method:
{actionDescriptor.ControllerName}.{actionDescriptor.ActionName}");
}
}
public class ExchangeDefinition {
public static final String CHECKPOINT_EXCHANGE = "ricta.checkpoint.exchange";
public static final String KEY_CHECKPOINT_REQUEST = "checkpoint.check.request";
}
@Configuration
public class CheckPointExchangeConfig implements RabbitListenerConfigurer {
@Autowired
ConnectionFactory connectionFactory;
@Bean
public Exchange checkPointEventExchange() {
return new TopicExchange(CHECKPOINT_EXCHANGE);
}
@Override
public void configureRabbitListeners(final RabbitListenerEndpointRegistrar registrar) {
registrar.setMessageHandlerMethodFactory(messageHandlerMethodFactory());
}
@Bean
public Jackson2JsonMessageConverter producerJackson2MessageConverter() {
return new Jackson2JsonMessageConverter();
}
@Bean
public MappingJackson2MessageConverter consumerJackson2MessageConverter() {
return new MappingJackson2MessageConverter();
}
@Bean
public DefaultMessageHandlerMethodFactory messageHandlerMethodFactory() {
DefaultMessageHandlerMethodFactory factory = new DefaultMessageHandlerMethodFactory();
factory.setMessageConverter(consumerJackson2MessageConverter());
return factory;
}
@Bean
public RabbitTemplate rabbitTemplate(final ConnectionFactory connectionFactory) {
final RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
rabbitTemplate.setMessageConverter(producerJackson2MessageConverter());
return rabbitTemplate;
}
}
然后,您需要声明并绑定您的队列。同样,在一个单独的类中:
public class QueueDefinition {
public static final String QUEUE_CHECKPOINT_REQUEST = KEY_CHECKPOINT_REQUEST;
}
@Configuration
public class CheckPointQueueConfig implements RabbitListenerConfigurer {
@Bean
public Queue queueCheckpointRequest() {
return new Queue(QueueDefinition.QUEUE_CHECKPOINT_REQUEST);
}
@Bean
public Binding checkPointRequestBinding
(Queue queueCheckpointRequest, Exchange checkPointEventExchange) {
return BindingBuilder
.bind(queueCheckpointRequest)
.to(checkPointEventExchange)
.with(KEY_CHECKPOINT_REQUEST)
.noargs();
}
@Autowired
DefaultMessageHandlerMethodFactory messageHandlerMethodFactory;
@Override
public void configureRabbitListeners(final RabbitListenerEndpointRegistrar registrar) {
registrar.setMessageHandlerMethodFactory(messageHandlerMethodFactory);
}
}
using (var connection = ConnectionFactory.CreateConnection())
using (var channel = connection.CreateModel())
{
//
// At one place in time, you have to declare the exchange and topic queues, and bind them
//
var queue = channel.QueueDeclare(queue: "checkpoint.check.request",
durable: true,
exclusive: false,
autoDelete: false,
arguments: null);
channel.ExchangeDeclare("ricta.checkpoint.exchange",
ExchangeType.Topic);
channel.QueueBind(queue.QueueName,
"ricta.checkpoint.exchange",
"checkpoint.check.*"
);
string message = Id.ToString();
var body = Encoding.UTF8.GetBytes(message);
IBasicProperties props = channel.CreateBasicProperties();
props.AppId = "DEMO-APP";
DateTime now = DateTime.UtcNow;
long unixTime = ((DateTimeOffset)now).ToUnixTimeSeconds();
props.Timestamp = new AmqpTimestamp(unixTime);
props.Type = "application/json";
props.Headers = new Dictionary
{
{ "__TypeId__", "java.lang.String" }
};
channel.BasicPublish(exchange: "ricta.checkpoint.exchange",
routingKey: "checkpoint.check.request",
basicProperties: props,
body: body);
Console.WriteLine(" [x] Sent {0}", message);
}
通过RabbitMQ.Client以下方式接收队列消息:
{
var factory = new ConnectionFactory { HostName = "localhost" };
//
// create connection
//
_connection = factory.CreateConnection();
//
// create channel
//
_channel = _connection.CreateModel();
_channel.ExchangeDeclare("ricta.checkpoint.exchange", ExchangeType.Topic, true);
_channel.QueueDeclare("ricta.check.request", true, false, false, null);
_channel.QueueBind("ricta.check.request", "ricta.checkpoint.exchange",
"checkpoint.check.*", null);
_channel.BasicQos(0, 1, false);
//
// Create Consumer of messages
//
var consumer = new EventingBasicConsumer(_channel);
consumer.Received += (ch, ea) =>
{
//
// handle the received message
//
HandleMessage(ea);
_channel.BasicAck(ea.DeliveryTag, false);
};
...
private void HandleMessage(BasicDeliverEventArgs args)
{
//
// received message, app id and time
//
var content = System.Text.Encoding.UTF8.GetString(args.Body);
var appId = args.BasicProperties.AppId;
var checkTime = System.DateTimeOffset.FromUnixTimeMilliseconds
(args.BasicProperties.Timestamp.UnixTime).ToLocalTime().DateTime;
....
}
}
Given a sorted linked list, delete all duplicates such that each element appear only once.
For example,Given 1->1->2, return 1->2.Given 1->1->2->3->3, return&
在JDK1.5之前的单例实现方式有两种(懒汉式和饿汉式并无设计上的区别故看做一种),两者同是私有构
造器,导出静态成员变量,以便调用者访问。
第一种
package singleton;
public class Singleton {
//导出全局成员
public final static Singleton INSTANCE = new S