Spring注解组合实现原理
我们在Spring和Spring boot使⽤过程中会发现,我们时常会⽤@RestController代替@Controller+@ResponseBody(很可惜,很多⼈还在混⽤)通过看@RestController
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Controller
@ResponseBody
public @interface RestController {
/**
* The value may indicate a suggestion for a logical component name,
* to be turned into a Spring bean in case of an autodetected component.
* @return the suggested component name, if any (or empty String otherwise)
* @since 4.0.1
*/
String value() default "";
}
明显的,@RestController包含了@Controller+@ResponseBody,这样也可以是的
看下Spring的考量:
⼤量的注解虽然简化了配置(如@Controller+@ResponseBody),但是⼀旦多了起来,同样难以清晰,所以,Spring提供了⼀个专⽤的ClassReader,可以解析注解上的注解,便于我们通过场景进⾏组合使⽤,⽽对外来说,就只是⼀个语义明确的注解
(@RestController)。
同样的,对于所有使⽤到注解的地⽅,均可以这样使⽤,⽐如,假设我们的配置类有⼀个通⽤的启⽤
逻辑:
条件1成⽴
条件2成⽴
.......
⾸先我们想到的是集成Condition,并实现条件判断,这样,n个Condition就开发出来了,接下⾥使⽤时就是有⼏个配置类每个写⼀坨
@XXCondition
@YYCondition
...
public class ZConfiguration{
...
}
@XXCondition
@YYCondition
...
public class WConfiguration{
...
}
...
然后,想到了⼀个虚拟注解,仅⽤⼀个来代表
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@XXCondition
@YYCOndition
...
public @interface TotalCondition {
...
}
so,我们的配置类就变成了这个样⼦
@TotalCondition
public class ZConfiguration{
...
}
@TotalCondition
public class WConfiguration{
...
}
...
好了,今天就到这⼉了
附 代码实现:springboot aop
废话不多说,直接上!!先来了⼀段⽐较难看的代码
Spring在初始化bean时其中⼀步是获取bean的MetadataVisitor,⽤于将class⽂件中该类的注解信息、属性等解析出来,今天我们要说的就是注解的解析,以下⽅法为总的⼊⼝
org.springframework.asm.ClassReader#accept(org.springframework.asm.ClassVisitor, org.springframework.asm.Attribute[], int)
......
// visits the class annotations and type annotations
if (ANNOTATIONS && anns != 0) {
for (int i = readUnsignedShort(anns), v = anns + 2; i > 0; --i) {
// row num 676
v = readAnnotationValues(v + 2, c, true,
classVisitor.visitAnnotation(readUTF8(v, c), true));
}
}
......
/**
* Reads the values of an annotation and makes the given visitor visit them.
*
* @param v
* the start offset in {@link #b b} of the values to be read
* (including the unsigned short that gives the number of
* values).
* @param buf
* buffer to be used to call {@link #readUTF8 readUTF8},
* {@link #readClass(int,char[]) readClass} or {@link #readConst
* readConst}.
* @param named
* @param named
* if the annotation values are named or not.
* @param av
* the visitor that must visit the values.
* @return the end offset of the annotation values.
*/
// row num 2006
private int readAnnotationValues(int v, final char[] buf,
final boolean named, final AnnotationVisitor av) {
int i = readUnsignedShort(v);
v += 2;
if (named) {
for (; i > 0; --i) {
v = readAnnotationValue(v + 2, buf, readUTF8(v, buf), av);
}
} else {
for (; i > 0; --i) {
v = readAnnotationValue(v, buf, null, av);
}
}
if (av != null) {
av.visitEnd();
}
return v;
}
......
/**
* Reads a value of an annotation and makes the given visitor visit it. *
* @param v
* the start offset in {@link #b b} of the value to be read
* (<i>not including the value name constant pool index</i>).
* @param buf
* buffer to be used to call {@link #readUTF8 readUTF8},
* {@link #readClass(int,char[]) readClass} or {@link #readConst * readConst}.
* @param name
* the name of the value to be read.
* @param av
* the visitor that must visit the value.
* @return the end offset of the annotation value.
*/
// row num 2041
private int readAnnotationValue(int v, final char[] buf, final String name, final AnnotationVisitor av) {
int i;
if (av == null) {
switch (b[v] & 0xFF) {
case 'e': // enum_const_value
return v + 5;
case '@': // annotation_value
return readAnnotationValues(v + 3, buf, true, null);
case '[': // array_value
return readAnnotationValues(v + 1, buf, false, null);
default:
return v + 3;
}
}
switch (b[v++] & 0xFF) {
case 'I': // pointer to CONSTANT_Integer
case 'J': // pointer to CONSTANT_Long
case 'F': // pointer to CONSTANT_Float
case 'D': // pointer to CONSTANT_Double
av.visit(name, readConst(readUnsignedShort(v), buf));
v += 2;
break;
break;
case 'B': // pointer to CONSTANT_Byte
av.visit(name, (byte) readInt(items[readUnsignedShort(v)]));
v += 2;
break;
case 'Z': // pointer to CONSTANT_Boolean
av.visit(name,
readInt(items[readUnsignedShort(v)]) == 0 ? Boolean.FALSE : Boolean.TRUE);
v += 2;
break;
case 'S': // pointer to CONSTANT_Short
av.visit(name, (short) readInt(items[readUnsignedShort(v)]));
v += 2;
break;
case 'C': // pointer to CONSTANT_Char
av.visit(name, (char) readInt(items[readUnsignedShort(v)]));
v += 2;
break;
case 's': // pointer to CONSTANT_Utf8
av.visit(name, readUTF8(v, buf));
v += 2;
break;
case 'e': // enum_const_value
av.visitEnum(name, readUTF8(v, buf), readUTF8(v + 2, buf));
v += 4;
break;
case 'c': // class_info
av.visit(name, Type(readUTF8(v, buf)));
v += 2;
break;
case '@': // annotation_value
v = readAnnotationValues(v + 2, buf, true,
av.visitAnnotation(name, readUTF8(v, buf)));
break;
case '[': // array_value
int size = readUnsignedShort(v);
v += 2;
if (size == 0) {
return readAnnotationValues(v - 2, buf, false,
av.visitArray(name));
}
switch (this.b[v++] & 0xFF) {
case 'B':
byte[] bv = new byte[size];
for (i = 0; i < size; i++) {
bv[i] = (byte) readInt(items[readUnsignedShort(v)]);
v += 3;
}
av.visit(name, bv);
--v;
break;
case 'Z':
boolean[] zv = new boolean[size];
for (i = 0; i < size; i++) {
zv[i] = readInt(items[readUnsignedShort(v)]) != 0;
v += 3;
}
av.visit(name, zv);
-
-v;
break;
case 'S':
short[] sv = new short[size];
for (i = 0; i < size; i++) {
sv[i] = (short) readInt(items[readUnsignedShort(v)]);
v += 3;
v += 3;
}
av.visit(name, sv);
--v;
break;
case 'C':
char[] cv = new char[size];
for (i = 0; i < size; i++) {
cv[i] = (char) readInt(items[readUnsignedShort(v)]);
v += 3;
}
av.visit(name, cv);
--v;
break;
case 'I':
int[] iv = new int[size];
for (i = 0; i < size; i++) {
iv[i] = readInt(items[readUnsignedShort(v)]);
v += 3;
}
av.visit(name, iv);
--v;
break;
case 'J':
long[] lv = new long[size];
for (i = 0; i < size; i++) {
lv[i] = readLong(items[readUnsignedShort(v)]);
v += 3;
}
av.visit(name, lv);
--v;
break;
case 'F':
float[] fv = new float[size];
for (i = 0; i < size; i++) {
fv[i] = Float
.intBitsToFloat(readInt(items[readUnsignedShort(v)]));
v += 3;
}
av.visit(name, fv);
--v;
break;
case 'D':
double[] dv = new double[size];
for (i = 0; i < size; i++) {
dv[i] = Double
.longBitsToDouble(readLong(items[readUnsignedShort(v)]));
v += 3;
}
av.visit(name, dv);
--v;
break;
default:
v = readAnnotationValues(v - 3, buf, false, av.visitArray(name));
}
}
return v;
}
在2041⾏处的⽅法上,通过‘@’⼜重新进⾏迭代,即会将该类上本⾝的注解进⾏迭代查,作为她的注解,进⾏注解的组合。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论