preface

This chapter mainly belongs to the Advanced Java section. If you are new to Java or have no programming background, you are not recommended to read this section. You can return to the basic part of the previous chapter.

  • What are annotations
  • What reflection can be used for
  • Faceted programming (including use of AOP provided by Spring)

Transfer the anchor

  • blog
  • github

annotations

What is the annotation

In a more abstract sense, it is used to mark the program, and these tags are read at class load, compile, run time, and finally respond to the processing. Annotations themselves are also a configuration. In traditional development, we configure our programs through various configuration files such as XML and YML, and when a large number of configuration files are configured, there is no doubt that the code readability is poor. With annotations, we can easily label the program with a clear table name for what it is used for. Look at an example of a note:

@RestController
@RequestMapping("/api")
public class ConsumeController {

    @RequestMapping("/hello/user")
    @ResponseBody
    public User hello(a) {
        returnuserService.hello(); }}Copy the code

If you have studied SpringBoot, you will be familiar with this part of the annotation provided by the Spring framework. This is a simple Api interface. We can see that classes and methods are marked with @ symbols. There will be a whole article on this later, but you just need to know what annotations look like when you use them.

Write a note

Let’s start with a full annotation definition:

@Target(ElementType.TYPE) // Enumeration of class interfaces
@Retention(RetentionPolicy.RUNTIME) / / runtime
@Inherited / / can be inherited
@Documented
public @interface Log1 {
    String info(a) default "";
}
Copy the code
  • @target (elementType. TYPE) specifies the TYPE of action that can be applied to classes, interfaces, and enumerations
  • @Retention(retentionPolicy.runtime) Indicates that the Retention effect is at RUNTIME
  • @inherited indicates Inherited. When used with @aliasfor (value=”xx”), this is an example
  • Documented is whether or not a Java DOC is generated, and that’s what we normally put in there
  • @interface syntax declaration, nothing to say
  • String info() default “”; Just to be clear, this is not a method of the Log1 annotation, it’s a property of it, you can think of it as a field, String is the type, default is the default.

Using annotations

Now that we’ve defined it, how do we use it? It’s as simple as adding the annotations we define to the concrete class:

@Log1(info = "info")
public class AnnoTest {}
Copy the code

Perhaps you still have doubt ❓, I added seems to have no what effect ah, not urgent, this is the next link I want to talk about reflection

reflection

What is a reflection

Reflection literally means not from the front but from the back…

Wrong, let’s see from an example (Java built-in reflection) :

public static void reflect(a) {
    // Built-in reflectionClass<? > annoClass =null;
    try {
        // Get the object
        annoClass = Class.forName("com.java.lang.base.annotation.AnnoTest");

        // Determine if there is an annotation log1
        boolean isAnnoLog1 = annoClass.isAnnotationPresent(Log1.class);
        Log.info("anno log1 exist: " + isAnnoLog1); // true

        if (isAnnoLog1) {
            // Get the annotation
            Log1 annotation = annoClass.getAnnotation(Log1.class);
            Log.info("info ----"+ annotation.info()); }}catch(Exception e) { Log.info(e.getMessage()); }}Copy the code

Let’s take a look at the above code and do the following

  • AnnoClass is an annoClass that assigns values to target classes. It can be left undefined, but for safety.
  • To avoid an exception, we use try and catch to catch it
  • Class.forname (” com. Java. Lang. Base. The annotation. AnnoTest “), in the form of a package name for the target Class here, so we can get information of the target Class
  • annoClass.isAnnotationPresentCheck whether the class existsLog1The return type is Boolean.
  • annoClass.getAnnotation(Log1.class)Gets an annotation applied to the class so that it can be usedannotation.info()Get the content information, remember@Log1(info = "info")This mark? This gets the original annotation information that was applied to the class at the time

Perhaps you still have doubt ❓ this also seems to have no what use ah, obtain the information, then?

If you have a scenario where you need to Log a class while it’s executing, would you want to manually call a Log method for each class? You might say let me write a public method, right? Write a public method, but how do I get information about the class? These are all problems, of course, must be that, but also can, annotations are not a little more handsome. All right, let me show you one more thing.

Application of reflection

To make this clear, make a few changes to the Log1 annotation:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Log1 {
    String info(a) default "";
}
Copy the code

Change @target (ElementType.TYPE) to @target (ElementType.METHOD).

public class AnnoTest {

    @Log1(info="info")
    public String hello(String msg) {
        System.out.println("Dynamic setting --" +  msg);
        return "Return value ---->"+ msg; }}Copy the code

Changed the object, this time in the method, let’s change the reflection code again:

 public static void reflect(a) {
    // Built-in reflectionClass<? > annoClass =null;
    try {
        // Get the object
        annoClass = Class.forName("com.java.lang.base.annotation.AnnoTest");
        // Get method
        Method[] methods = annoClass.getDeclaredMethods();
        // method traversal:
        for (Method declaredMethod : methods) {
            // Determine if the method has annotations
            boolean isAnnoLog = declaredMethod.isAnnotationPresent(Log1.class);
            if(isAnnoLog) {
                annotation = declaredMethod.getAnnotation(Log1.class);
                // Get the constructorConstructor<? > constructor = annoClass.getConstructor();/ / instantiate
                Object obj = constructor.newInstance();
                // Execute method - executes annotated dataLog.info(declaredMethod.invoke(obj, annotation.info())); }}}catch(Exception e) { Log.info(e.getMessage()); }}Copy the code

The big changes in the above code are mainly in the method of the piece, let’s talk about the specific method:

  • Method[] methods = annoClass.getDeclaredMethods(); This is getting the method defined on the target class

  • Followed by traversal method, Boolean isAnnoLog = declaredMethod. IsAnnotationPresent (Log1. Class); Determines whether there are annotation tags on the method.

  • We then get the annotation, Constructor
    constructor = annoClass.getConstructor(); This means to get the constructor of the class for the following instantiation.

  • Object obj = constructor.newInstance(); Instantiate the class.

  • Declaredmethod.invoke (obj, annotation.info()) means to execute a specific method and pass the parameter.

So what you can see from this example is, I didn’t do anything, we used to instantiate it first and then execute it, but now with an annotation, this class method executes. Well, at this point, I think you have some understanding of reflection and annotations.

Now to summarize what reflection is:

::: tip Each Class has a Class object that contains information about the Class. When a new class is compiled, a.class file of the same name is generated, the contents of which hold the class object. Class loading is equivalent to the loading of Class objects, and classes are dynamically loaded into the JVM the first time they are used. You can also use class.forname (” XXX “). This way to control the loading of a Class, the method returns a Class object. Reflection can provide information about a class at run time, and the class can be loaded at run time, even if its.class does not exist at compile time. : : :

Class provides support for reflection along with java.lang.reflect. The Java.lang. Reflect library consists of three classes:

  • Field: You can use the get() and set() methods to read and modify the fields associated with the Field object;
  • Method: You can use the invoke() Method to call a Method associated with a Method object;
  • Constructor: Use Constructor’s newInstance() to create new objects;

You can also try to output it on the console, but I’m not going to do it here.

Addition of notes

Why add it in this chapter? Because it requires reflection to help you understand it better. Mainly supplement the following knowledge points:

  • @Annotation inheritance
  • Display passing and implicit passing of @ annotations

Let’s use an example to illustrate these two points:

@Target(ElementType.TYPE) // Enumeration of class interfaces
@Retention(RetentionPolicy.RUNTIME) / / runtime
@Inherited / / can be inherited
@Documented
// Inherit Log2 annotations
@Log2
public @interface Log1 {

    // Display the value of the attribute passed here that can receive err
    // The display of Courier should be marked with @aliasfor, and default should be consistent
    @AliasFor(value="err")
    String info(a) default "";

    @AliasFor(value="info")
    String err(a) default "";

    // implicitly pass - attribute name with Log2 attribute name
    @AliasFor(annotation = Log2.class, attribute = "log2")
    String err1(a) default "";

    @AliasFor(annotation = Log2.class, attribute = "log2")
    String err2(a) default "";
}
Copy the code
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Log2 {
    String log2(a) default "";
}
Copy the code
@log1 (err1 = "implicitly pass err1")
public class AnnoTest {}Copy the code
 public static void reflect(a) {
    // Built-in reflectionClass<? > annoClass =null;
    try {
        // Get the object
        annoClass = Class.forName("com.java.lang.base.annotation.AnnoTest");

        // Determine if there is an annotation log1
        boolean isAnnoLog1 = annoClass.isAnnotationPresent(Log1.class);
        Log.info("anno log1 exist: " + isAnnoLog1); // true

        Log1 annotation = annoClass.getAnnotation(Log1.class);
        // Log.info("info ----" + annotation.info()); // info ---- explicitly pass info

        // THE AOP version gets annotations
        annotation = AnnotationUtils.getAnnotation(annoClass, Log1.class);
        Log.info("err1 ----" + annotation.err1()); // Implicitly pass err1
        Log.info("err2 ----" + annotation.err2()); Err2 - @log1 (err1 = "implicitly passed err1")


        
    } catch(Exception e) { Log.info(e.getMessage()); }}Copy the code

People speaking

Posted these several pieces of code, meng force is very understanding. For now, annotation inheritance is nothing to talk about, and can be applied directly to annotations, just like classes can get it. Let’s talk about attribute passing.

First, the @ annotation is explicitly passed:

@AliasFor(value="err")
String info(a) default "";

@AliasFor(value="info")
String err(a) default "";
Copy the code

So this @aliasfor is passing the attribute, value=”err” is passing the display, err is String err() default “”; This property right here. What does it do? What it does is if I pass a value to the info field and err doesn’t, it will pass by default to String err() default “”; This property, if it’s a little abstract, you can console it out and you’ll see.

@annotation implicitly passed:

// implicitly pass - attribute name with Log2 attribute name
@AliasFor(annotation = Log2.class, attribute = "log2")
String err1(a) default "";

@AliasFor(annotation = Log2.class, attribute = "log2")
String err2(a) default "";
Copy the code

Annotation = Log2. Class, attribute = “Log2”. It inherits the name of the property Log2, and you’ll notice that it’s not the same as the value of the property Log2. That’s the benefit of implicit delivery. So the next time we’re going to apply it to a class, instead of writing the property name, we can just say at sign Log(“hh”). If you’ve learned about Spring you’ll notice that a lot of annotations you use don’t have a property name, like @value (” XXXX “). In addition, as above, you can pass attribute values to each other.

AOP

In fact, this section is the supplement and summary of the previous section, AOP is the acronym of Aspect Oriented Program, referred to as section-oriented programming. We’ve talked about object-oriented programming before, and the features of object-oriented programming: inheritance, polymorphism, and encapsulation. Let me tell you what AOP is in the most straightforward terms.

OOP is what we call object-oriented ::: :

What is the AOP

To take an example of building a car, in OOP thinking, building a car is built like this. Car -> shell -> chassis -> wheels, suppose there are these parts, if one day the boss has a new idea, I want to change the car, does that have to be torn down, each to rebuild? Pull the whole body. We write programs are the same, which day the product said to change a requirement, take the front end for example, change a button will not change the style of the entire page.

After OOP, we are looking at how APO makes cars, wheels > chassis > shell > car. We find that if WE want to change a place, we just need to cut to a specific point (cut point) and do a specific thing. At this time, you can tell the boss, where do you want to change? I’ll get it done for you tonight, and then the boss gives you a raise.

Inversion of Control Inversion of Control Inversion of Control Inversion of Control Inversion of Control Spring is a core part of the Spring framework and a common interview question. Here, do not do too much introduction, Spring source did not understand, it does not matter, the concept of the first clear. What are the benefits of Spring IOC? , just also borrowed his example, I think it is good, to share with you.

The scene again

Back to the point, we took the example of building a car, walked through the concept, and went back to the journaling scenario we talked about earlier. We’ve talked about using the public print log method as well. Now I want to ask a question. If I change this method, can you guarantee that the dependent classes will not be affected? Obviously, regardless of the impact, you’re not sure right now. Okay, you’re hesitating.

Instead of AOP, you just need to cut into the specified class and the method of the class, do some processing, this at run time, dynamic code into the specified method of the class, the specified location of the programming idea is faceted, is not so easy.

There are many popular frameworks that use AOP ideas, such as Spring-AOP, some of the interceptor frameworks, almost all have its shadow. Said so much, not to tell you OOP is not handsome AOP, after all use AOP to write code, handsome can not be a meal, in fact, AOP is a supplement of OOP, make up for some shortcomings in OOP, the purpose is to make our program more robust, by the way, we want to put an end to fancy coding, Make the hole as small as possible.

How is AOP used in Spring

Spring-aop encapsulates a lot of functionality for us. Let’s take a look at how to use it with an example. If you haven’t learned Spring yet, I’ve added comments to the code.

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Log3 {
    String hello(a) default "";
}
Copy the code
@Aspect
@Component
public class SpringAopMain {

    / / point of tangency
    @Pointcut("@annotation(com.java.lang.base.annotation.Log3)")
    public void aspect(a) {}

    // Configure pre-notification using the pointcut registered on method aspect()
    // The JoinPoint pointcut object can be accepted without this parameter
    @Before("aspect()")
    public void Before(a) {
        Log.info("before ....");
    }

    // post notification
    @After("aspect()")
    public void After(JoinPoint point) {
        Log.info("after ...." + point.toString());
    }

    // Final notification - sets the return value to String
    @AfterReturning(pointcut = "aspect()", returning = "res")
    public void AfterReturning(String res) {
        Log.info("----AfterReturning method starts execution :--"+res);
    }

    // Exception notification
    @AfterThrowing(pointcut="aspect()",throwing="e")
    public void AfterThrowing(Throwable e) {
        Log.info("The -----AfterThrowing method starts executing :"+e);
    }

    // @around annotations can be used to accomplish specific tasks before and after a specific method is called.
    // The return value is equal to the return value of the method
    @Around("aspect()")
    public Object Around(ProceedingJoinPoint joinPoint) throws Throwable {
        Log.info("Method executed");
        Signature signature = joinPoint.getSignature();
        // Get the annotation binding method
        Method method = ((MethodSignature)signature).getMethod();
        Log3 annotation = AnnotationUtils.getAnnotation(method, Log3.class);

        Log.info("aop log3 --->" + annotation.hello());

        // Get the input parameter
        Object[] inputArgs = joinPoint.getArgs();
        // Get the parameter name
        String[] argNames = ((MethodSignature) signature).getParameterNames();
        Map<String, Object> paramMap = new HashMap<>();
        for(int i = 0; i < argNames.length; i++) {
            paramMap.put(argNames[i], inputArgs[I]);
        }

        Log.info("Into the participation" + paramMap.toString());

        // Modify the input parameter
        inputArgs[0] = "spring aop args";
        // Execute method
        Object result = joinPoint.proceed(inputArgs);

        Log.info( "Reflection result ----->"+ result);

        // Return the result
        returnresult; }}Copy the code

As you can see, the code does not point to a specific class. Instead, it uses the Log3 annotation as a pointcut to do some processing. When the annotation is applied to the target class, it will automatically do the processing

This is the end of the chapter, next time we will talk about enumerations and generics, pay attention to the ~

Blog address for more content ~