An overview of the

The ultimate goal of Spring is to simplify application development. Colloquially speaking, reduce repetitive code and write less code to achieve the same goal. AOP (Aspect Oriented Programming) is a way to reduce code duplication. As we all know, JAVA is an OOP (Object Oriented Programming) language, in which function modules are abstracted into objects. These objects through a certain connection to complete the application we see, one service after another. Its core is the Object.

To understand aspect programming, you need to understand what aspect is. Divide a watermelon into two pieces with a knife, and the cut is the cut surface; Cooking, pot and stove together to complete the cooking, pot and stove are the noodles. In web hierarchy design, the Web layer -> Gateway layer -> services layer -> data layer, each layer is also a section. In programming, object to object, method to method, module to module are all facets.

Classes should be pure and should not contain logic that is independent of themselves. Single responsibility principle.

Faceted programming, which can lead to code decoupling; At the same time, aspect programming also requires executing code, adding some extra code execution. Adapt to local conditions and use AOP.

His shan zhishi

  • Easily understand AOP (aspect oriented programming) : www.cnblogs.com/Wolfmanlq/p…
  • AOP that something: aspect oriented programming: my.oschina.net/huangyong/b…
  • OOP perfect ornament – SpringAOP implementation principle of AOP: www.cnblogs.com/chenjunping…
  • Spring series of AOP: www.cnblogs.com/xiaoxi/p/59…

Concrete understanding

When we do activities, we usually check the validity of each interface (whether it starts, whether it ends, etc.) and whether the interface requires user login.

Logical, we could do that.

The problem with this is that there are as many interfaces as there are code copies. For a “lazy person”, this is intolerable. Well, come up with a common method that each interface calls. There’s a little bit of a cut in there.

The problem is that I don’t have to copy the code every time, but every interface has to call this method. Here comes the concept of facets, where I inject a method somewhere in the interface call (the pointcut).

In this way, the interface only needs to care about the specific business and does not need to care about other logic or processing that is not the concern of the interface.

In the red box, that’s programming for facets.

The theory of

Before using AOP, we need to understand a few concepts.

Join Point

All possible areas that need to be injected into the section. Such as before and after methods, class initialization, property initialization, and so on.

Poincut

Join points that need to do some processing, such as printing logs, processing caches, and so on. How to specify a tangent point? Spring uses AspectJ’s pointcut expression language to define Spring facets.

Multiple expressions can be logically connected using AND, OR, or not.

The more complicated part is execution.

Currently, Spring only supports method pointcut definitions

Advice

Define what to do when. Spring supports five notification types on methods

Aspect

A collection of notifications + pointcuts that define what to do where and when.

Introduction

Allows us to add new method attributes to existing classes. Isn’t that just applying the aspect (defined by the new method property: advice) to the target class

Target

The target class mentioned in the introduction is the object to be notified of. Real business logic, which we can weave into the surface without even knowing it. I focus on the logic of the business itself.

Weaving

The process of creating a new proxy object by applying a facet to the target object.

AOP implementation principles in Spring

AOP implementations actually use the proxy pattern.

The agent

The concept of proxy: a simple understanding is that by creating a proxy object for an object, we do not directly refer to the original object, but the creation of the proxy object controls the reference to the original object.

There are two proxy classes, based on when the agent was created.

  • Static proxy: source code created by a programmer or automatically generated by a specific tool and then compiled. The.class file for the proxy class exists before the program runs.
  • Dynamic proxy: when the program is running, it is created dynamically by using reflection mechanism, without manual writing code. Dynamic proxies not only simplify programming but also improve the extensibility of software systems because Java reflection can generate any type of dynamic proxy class.

Proxy principle: Proxy objects contain internal references to real objects so that they can manipulate real objects, and provide the same interface as real objects so that they can replace real objects at any time. At the same time, a proxy object can perform operations on the real object with additional operations attached, which is equivalent to encapsulating the real object.

Spring uses dynamic proxies.

JDK for dynamic proxy

The Java JDK itself supports dynamic creation of proxy objects.

Java’s dynamic proxy has the disadvantage that it only supports classes that implement the interface. Therefore, it is possible to introduce proxies for classes supported by the cGLIb (Code Generation Library) tripartite Library. The JDK dynamic proxy interested can refer to: blog.csdn.net/u012410733/…

Dynamic proxy of CGLIB

Interested in additional libraries can consult: blog.csdn.net/danchu/arti…

The sample

There is a requirement to cache or log certain interfaces. You don’t want to call caching or print logging methods on every interface. You can do it this way. Code:

  • Define Animal abstract interface: Animal
  • Define the specific animal Cat: Cat
  • Define the bean scan configuration class: AnimalConfig
  • Define the Cache annotation: Cache
  • Define the CacheAspect: CacheAspect
  • Define the LogAspect: LogAspect
  • Define the test entry class: App

1. The Animal interface

package bean;

public interface Animal {

    public String sayName(String name, Integer num);
}
Copy the code

2. The Cat class

package bean;

import org.springframework.stereotype.Component;

@Component
public class Cat implements Animal {

    @Cache(60)
    public String sayName(String name, Integer num) {
        return "this is cat " + name + ","+ num; }}Copy the code

AnimalConfig Spirng configures the scan class

package bean;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration
@ComponentScan
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class AnimalConfig {}Copy the code

4.Cache annotations (used with CacheAspect)

package bean;

import java.lang.annotation.*;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Cache {
    int value(a) default 0;
}
Copy the code

5.CacheAspect

package bean;

import com.alibaba.fastjson.JSONObject;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.LinkedHashMap;
import java.util.Map;

@Component
@Aspect
@Order(1000)
public class CacheAspect {

    // Define pointcuts: methods with Cache annotations
    @Pointcut("@annotation(Cache)")
    private void cache(a){}

    // Temporary storage area
    private static Map<String, Object> cacheList = new LinkedHashMap<String, Object>();

    // Define surround notification, handle interface/method add cache
    @Around("cache()")
    private Object cacheAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
        Object object = proceedingJoinPoint.getTarget();
        Object[] args = proceedingJoinPoint.getArgs();
        String className = object.getClass().getName();
        MethodSignature signature = (MethodSignature)proceedingJoinPoint.getSignature();
        Method method = signature.getMethod();
        
        // Assemble the cache key
        String cacheKey = className + "_" + method.getName() + "_" + JSONObject.toJSONString(args);
        if (cacheList.containsKey(cacheKey)){
            System.out.println("data get cache");
            return cacheList.get(cacheKey);
        }else {
            System.out.println("data get db");
            Object result = proceedingJoinPoint.proceed();
            cacheList.put(cacheKey, result);
            returnresult; }}}Copy the code

6.LogAspect LogAspect

package bean;

import com.alibaba.fastjson.JSONObject;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

@Component
@Aspect
@Order(100)
public class LogAspect {
    // Define the pointcut: public method sayName with arbitrary arguments, arbitrary return values
    @Pointcut("execution(public * *sayName(..) )")
    private void log(a){}
    
    // Define circular notification: handles log injection
    @Around("log()")
    private Object logAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        Object[] args = proceedingJoinPoint.getArgs();

        System.out.println("before, params:" + JSONObject.toJSONString(args));
        Object result = proceedingJoinPoint.proceed();
        System.out.println("after, result:" + JSONObject.toJSONString(result));
        returnresult; }}Copy the code

7. APP test entry class

import bean.Animal;
import bean.AnimalConfig;
import bean.Cat;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class App {
    public static void main(String[] args){
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AnimalConfig.class);

        Animal animal = applicationContext.getBean("cat", Cat.class);
        String result = animal.sayName("rudytan".12);
        String result1 = animal.sayName("rudytan".12);
        String result2 = animal.sayName("rudytan".12);
        String result3 = animal.sayName("rudytan".13);
        String result4 = animal.sayName("rudytan".13); System.out.println(result); }}Copy the code

Description:

  • @cache is a custom annotation (to mark that the method requires caching)
  • @enableAspectJAutoProxy Indicates whether to enable cglib dynamic proxy
  • @aspect defines this class as an Aspect class
  • @order specifies the Order of execution when there are more than one aspect class.
  • @pointcut defines the current function as the Pointcut.
  • @around defines the surround notification