1: Introduction to Java Annotations
Annotations are often used in development, and I occasionally see custom annotations in projects. Today, let’s discuss what the annotation is, as well as the application scenarios of the annotation and how to customize the annotation.
The following lists common annotations in development
@Override: Used to identify that the method inherits from the superclass. When the method of the parent class is deleted or modified, the compiler will prompt an error message (you can always see this on the toString() method that we see most often)
@Deprecated: It means that this class or method is deprecated and has expired. If the user still wants to use it, a compilation warning will be generated.
@SuppressWarnings: Compiler warning message for ignore
Junit Test: @Test
Some annotations of Spring: @Controller, @RequestMapping, @RequestParam, @ResponseBody, @Service, @Component, @Repository, @Resource, @Autowire
Annotations for Java verification: @NotNull, @Email
Let's take a look at the true face of Mount Lu in the annotation Override.java
@Target(ElementType.METHOD)@Retention(RetentionPolicy.SOURCE)public @interface Override {} 2: Basic knowledge of Java annotation
1. Java annotation data type
Annotations are written in .java files and use @interface as the keyword, so annotations are also a data type of Java. From a broad definition, Class, Interface, Enum, and Annotation are all Class types.
2. Java meta annotation
When creating annotations, you need to use some annotations to describe the annotations you created, that is, the annotations written on @interface. These annotations are called meta annotations, such as @Target, @Retention, etc. seen in Override. Here are some meta annotations
@Documented: Used to mark whether the annotation is included when generating javadoc. You can see that this annotation is the same as @Override, the annotation is empty and there is nothing.
@Documented@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.ANNOTATION_TYPE)public @interface Documented {}@Target: used to define where annotations can be used. By default, it can be used anywhere, or it can specify the scope of use. In development, it is more common to use annotations on classes (such as @Controller), fields (such as @Autowire), methods (such as @RequestMapping), methods parameters (such as @RequestParam), etc.
TYPE: class, interface, or enum declaration
FIELD: Domain (attribute) declaration
METHOD: Method Declaration
PARAMETER: Parameter declaration
CONSTRUCTOR: Constructor method declaration
LOCAL_VARIABLE: Local variable declaration
ANNOTATION_TYPE: Comment type declaration
PACKAGE: Package Statement
Target.java
@Documented@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.ANNOTATION_TYPE)public @interface Target { /** * Returns an array of the kinds of elements an annotation type * can be applied to. * @return an array of the kinds of elements an annotation type * can be applied to */ ElementType[] value();} public enum ElementType { /** Class, interface (including annotation type), or enum declaration */ TYPE, /** Field declaration (includes enum constants) */ FIELD, /** Method declaration */ METHOD, /** Formal parameter declaration */ PARAMETER, /** Constructor declaration */ CONSTRUCTOR, /** Local variable declaration */ LOCAL_VARIABLE, /** Annotation type declaration */ ANNOTATION_TYPE, /** Package declaration */ PACKAGE, /** Type parameter declaration */ TYPE_PARAMETER, /** Use of a type */ TYPE_USE}@Inherited: Allows subclasses to inherit the annotations in the parent class, and can obtain the annotations of the parent class through reflection.
@Documented@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.ANNOTATION_TYPE)public @interface Inherited {}@Constraint: used to verify whether the attribute value is legal
@Documented@Target({ElementType.ANNOTATION_TYPE})@Retention(RetentionPolicy.RUNTIME)public @interface Constraint { Class<? extends ConstraintValidator<?, ?>>[] validatedBy();}@Retention: The declaration cycle of annotation is used to define the survival stage of annotation. It can survive at the source code level, compilation level (byte code level), and runtime level.
SOURCE: Source code level, annotations are only present in the source code, and are generally used to interact with the compiler and are used to detect code. Such as @Override, @SuppressWarings.
CLASS: bytecode level, annotations exist in source code and bytecode files. They are mainly used to generate additional files during compilation, such as XML, Java files, etc., but cannot be obtained during runtime. For example, mybatis generates entity and mapping files. At this level, it is necessary to add a proxy (javaagent) when JVM is loaded, and use a proxy to dynamically modify the bytecode file.
RUNTIME: Runtime level, annotations exist in source code, bytecode, and Java virtual machines. They are mainly used for runtime, and reflection can be used to obtain relevant information.
@Documented@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.ANNOTATION_TYPE)public @interface Retention { /** * Returns the retention policy. * @return the retention policy */ RetentionPolicy value();} 3. Contents of Java annotations
In the above annotation source code, you can see that some annotations have no content, and some annotations have content, which seems to be like a method.
Syntax format of the annotated content: Data type attribute name () default default value, data type is used to describe the data type of the attribute. The default value means that when no attribute is assigned, the default value is used. Generally, String uses an empty string "" as the default value, and arrays generally use an empty array { } as the default value.
Let's take a look at the statement of the annotation of RequestMapping in SpringMVC
@Target({ElementType.METHOD, ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Documented@Mappingpublic @interface RequestMapping { String name() default ""; @AliasFor("path") String[] value() default {}; @AliasFor("value") String[] path() default {}; RequestMethod[] method() default {}; String[] params() default {}; String[] headers() default {}; String[] consumers() default {}; String[] produces() default {};}Using RequestMapping annotation in SpringMVC
@RequestMapping(value = "/list", method = RequestMethod.POST, produces = {"application/json;charset=UTF-8;"})public String list(){} 4. Use scenarios of annotations
You can analyze the usage scenarios of annotations through the declaration period of annotations:
SOURCE source code level: for compilers, such as @Override, @Deprecated, etc., there are not many scenarios that developers should use.
CLASS: Bytecode level, this part is rarely seen
RUNTIME: Runtime level, this is the most common, and almost all the annotations used by developers are runtime level. Runtime annotations are commonly used in the following situations
Annotation without any attributes in the annotation. This part of the annotation usually plays a role as annotation, such as @Test, @Before, @After. By obtaining these tag annotations, some logical processing is done.
You can use the constraint annotation @Constraint to verify the attribute value, such as @Email, @NotNull, etc.
You can configure some parameters by using properties in the annotation, and then you can use reflection to obtain these parameters. These annotations have no other special functions, they just simply configure some parameters instead of XML configuration. Using annotations to configure parameters This is popular in Spring boot, such as @Configuration
Regarding the configuration method xml vs annotation, generally use xml to configure some configurations that are not very close to the business relationship, and use annotations to configure some parameters that are closely related to the business.
Three: Java annotation and reflection basic API
// Get annotation of a certain type public <A extends Annotation> A getAnnotation(Class<A> annotationClass);// Get all annotations (including the annotations modified by Inherited in the parent class) public Annotation[] getAnnotations(); // Get the annotations declared (but does not include the annotations modified by Inherited in the parent class) public Annotation[] getDeclaredAnnotations();// Test whether an object is annotated by an annotation public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)// Get all fields declared by a certain class public Field[] getDeclaredFields() throws SecurityException;// Get a certain method public Method getMethod(String name, Class<?>... parameterTypes);
Four: Custom annotations
Use custom annotations + interceptors or AOPs to control permissions.
The following example is used to define an annotation to restrict the user's must log in when accessing an interface.
Step 1: Define the annotation
RequiresLogin.java
@Documented@Target({ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)public @interface RequiresLogin {}Step 2: Use annotations
@Controller@RequestMapping("/user")public class UserController { @RequiresLogin @RequestMapping(value = "/list", produces = {"application/json;charset=UTF-8;"}) public String getUserList(){ System.out.println("----------------------"); return "[{'id': 1, 'username':'zhangsan'}]"; }}Step 3: Use AOP to intercept and parse the annotations
public class LoginAdvices { public void before(JoinPoint joinPoint) throws Exception{ Object target = joinPoint.getTarget(); String methodName = joinPoint.getSignature().getName(); System.out.println(target + "-------" + methodName); Method method = target.getClass().getMethod(methodName); boolean annotationPresent = method.isAnnotationPresent(RequiresLogin.class); if (annotationPresent) { // The user must log in boolean isLogin = false; if (!isLogin) { throw new Exception("You must log in to access this interface"); } else { System.out.println("Login..."); } } }}Configure aop in applicationContext.xml
<bean id="loginAdvices"/> <!-- aop configuration--> <aop:config proxy-target-class="true"> <!-- section--> <aop:aspect ref="loginAdvices"> <!-- point--> <aop:pointcut id="pointcut1" expression="execution(* com.mengdee.manager.controller.*.*(..))"/> <!-- Connect notification method and point--> <aop:before method="before" pointcut-ref="pointcut1"/> </aop:aspect> </aop:config>
Custom exceptions
Why customize exceptions
Although Java provides a rich variety of exception handling classes, custom exceptions are often used in projects. The main reason is that the exception classes provided by Java still cannot meet the needs of various businesses in some cases. For example, some errors in the system comply with Java syntax, but do not comply with business logic. If the account does not exist when the user logs in or the account is locked, you can customize an account exception AccountException.
Or in some cases, the same exception in Java may be caused by multiple reasons. It is not easy to locate errors when troubleshooting problems. At this time, you can use a customization of a more clear exception.
Benefits of custom exceptions: Custom exceptions can make exceptions more clear and hide underlying exceptions, which is safer and more intuitive.
Use of custom exceptions: Custom exceptions are generally inherited from Exception or RuntimeException. According to business needs, some attributes can be taken as parameters of the constructor. Custom exceptions require programmers to manually throw exceptions and handle exceptions.
Below is an example of custom exceptions in Apache Shiro
public class ShiroException extends RuntimeException { public ShiroException() { } public ShiroException(String message) { super(message); } public ShiroException(Throwable cause) { super(cause); } public ShiroException(String message, Throwable cause) { super(message, cause); }}The above is a detailed description of Java annotation and custom annotations