Spring系列(11-15)
十一、lazy-init:bean延迟初始化
<bean lazy-init="是否是延迟初始化" />
十二、使用继承简化bean配置
<bean id="serviceA" class="com.javacode2018.lesson001.demo12.ServiceA"/> <bean id="baseService" abstract="true"> <property name="name" value="路人甲Java"/> <property name="serviceA" ref="serviceA"/> </bean> <bean id="serviceB" class="com.javacode2018.lesson001.demo12.ServiceB" parent="baseService"/> <bean id="serviceC" class="com.javacode2018.lesson001.demo12.ServiceC" parent="baseService"/>
十三、单例bean中使用多例bean
1、ApplicationContext接口的方式
<bean id="serviceA" class="com.javacode2018.lesson001.demo13.applicationcontextaware.ServiceA" scope="prototype"/>
public class ServiceA {
}
public class ServiceB implements ApplicationContextAware {
private ApplicationContext context;
public void say(){
ServiceA serviceA = this.getServiceA();
System.out.println("this:"+this+",serviceA:"+ serviceA);
}
public ServiceA getServiceA() {
return this.context.getBean(ServiceA.class);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.context = applicationContext;
}
}2、lookup-method方式实现
<bean id="serviceA" class="com.javacode2018.lesson001.demo13.lookupmethod.ServiceA" scope="prototype"/> <bean id="serviceB" class="com.javacode2018.lesson001.demo13.lookupmethod.ServiceB"> <lookup-method name="getServiceA" bean="serviceA"/> </bean>
3、replaced-method:方法替换
3.1、步骤一:定义替换者
public interface MethodReplacer {
/**
* @param obj 被替换方法的目标对象
* @param method 目标对象的方法
* @param args 方法的参数
* @return return value for the method
*/
Object reimplement(Object obj, Method method, Object[] args) throws Throwable;
}servieB的方法替换者
public class ServiceBMethodReplacer implements MethodReplacer, ApplicationContextAware {
@Override
public Object reimplement(Object obj, Method method, Object[] args) throws Throwable {
return this.context.getBean(ServiceA.class);
}
private ApplicationContext context;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.context = applicationContext;
}
}3.2、步骤二:定义替换者bean
<!-- 定义替换者bean --> <bean id="serviceBMethodReplacer" class="com.javacode2018.lesson001.demo14.ServiceBMethodReplacer" />
通过replaced-method元素配置目标bean需要被替换的方法
<bean id="serviceB" class="com.javacode2018.lesson001.demo14.ServiceB"> <replaced-method name="getServiceA" replacer="serviceAMethodReplacer"/> </bean>
name:用于指定当前bean需要被替换的方法。
replacer:替换者,即实现了MethodReplacer接口的类对应的bean。
十四、动态代理
1、jdk动态代理
java.lang.reflect.Proxy java.lang.reflect.InvocationHandler
1.1、java.lang.reflect.Proxy
getProxyClass()
public static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces);
loader:定义代理类的类加载器。
interfaces:指定需要实现的接口列表,创建的代理默认会按顺序实现interfaces指定的接口。
newProxyInstance()
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
这个方法先为指定的接口创建代理类,然后会生成代理类的一个实例,最后一个参数比较特殊,是InvocationHandler类型的,这个是个接口如下:
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
isProxy()
public static boolean isProxyClass(Class<?> cl)
getInvocationHandler()
public static InvocationHandler getInvocationHandler(Object proxy) throws IllegalArgumentException
案例1
public interface IService {
void m1();
void m2();
void m3();
}创建IService接口的代理对象
@Test
public void m1() throws Exception {
// 1. 获取接口对应的代理类
Class<IService> proxyClass = (Class<IService>)Proxy.getProxyClass(IService.class.getClassLoader(), IService.class);
// 2. 创建代理类的处理器
InvocationHandler invocationHandler = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("我是InvocationHandler,被调用的方法是:" + method.getName());
return null;
}
};
// 3. 创建代理实例
IService proxyService = proxyClass.getConstructor(InvocationHandler.class).newInstance(invocationHandler);
// 4. 调用代理的方法
proxyService.m1();
proxyService.m2();
proxyService.m3();
}案例2
@Test
public void m2() throws Exception {
// 1. 创建代理类的处理器
InvocationHandler invocationHandler = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("我是InvocationHandler,被调用的方法是:" + method.getName());
return null;
}
};
// 2. 创建代理实例
IService proxyService = (IService) Proxy.newProxyInstance(IService.class.getClassLoader(), new Class[] {IService.class}, invocationHandler);
// 3. 调用代理的方法
proxyService.m1();
proxyService.m2();
proxyService.m3();
}案例3:任意接口中的方法耗时统计
public class CostTimeInvocationHandler implements InvocationHandler {
private Object target;
public CostTimeInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws
Throwable {
long starTime = System.nanoTime();
Object result = method.invoke(this.target, args);
long endTime = System.nanoTime();
System.out.println(this.target.getClass() + ".m1()方法耗时(纳秒):" + (endTime - starTime));
return result;
}
/**
* 用来创建targetInterface接口的代理对象
*
* @param target 需要被代理的对象
* @param targetInterface 被代理的接口
* @param <T>
* @return
*/
public static<T> T createProxy(Object target, Class<T> targetInterface) {
if (!targetInterface.isInterface()) {
throw new IllegalStateException("targetInterface必须是接口类型!");
} else if (!targetInterface.isAssignableFrom(target.getClass())) {
throw new IllegalStateException("target必须是targetInterface接口的实现类!");
}
return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new CostTimeInvocationHandler(target));
}
}target:目标对象,需要实现targetInterface接口。
targetInterface:需要创建代理的接口。
invoke方法中通过 method.invoke(this.target, args) 调用目标方法,然后统计方法的耗时。
public interface IUserService {
/**
* 插入用户信息
* @param name
*/
void insert(String name);
}public class UserService implements IUserService {
@Override
public void insert(String name) {
System.out.println(String.format("用户[name:%s]插入成功!", name));
}
}直接使用CostTimeInvocationHandler来创建代理类
@Test
public void costTimeProxy() {
IService serviceA = CostTimeInvocationHandler.createProxy(new ServiceA(), IService.class);
IService serviceB = CostTimeInvocationHandler.createProxy(new ServiceB(), IService.class);
serviceA.m1();
serviceA.m2();
serviceA.m3();
serviceB.m1();
serviceB.m2();
serviceB.m3();
}2、cglib动态代理
案例1:拦截所有方法(MethodInterceptor)
public class Service1 {
public void m1() {
System.out.println("我是m1方法");
}
public void m2() {
System.out.println("我是m2方法");
}
}使用Enhancer来给某个类创建代理类,步骤
@Test
public void test1() {
//1.创建Enhancer对象
Enhancer enhancer = new Enhancer();
//2.通过setSuperclass来设置父类型,即需要给哪个类创建代理类
enhancer.setSuperclass(Service1.class);
/*3.设置回调,需实现org.springframework.cglib.proxy.Callback接口,
此处我们使用的是org.springframework.cglib.proxy.MethodInterceptor,也是一个接
口,实现了Callback接口,当调用代理对象的任何方法的时候,都会被MethodInterceptor接口的invoke方法处理*/
enhancer.setCallback(new MethodInterceptor() {
/**
* 代理对象方法拦截器
* @param o 代理对象
* @param method 被代理的类的方法,即Service1中的方法
* @param objects 调用方法传递的参数
* @param methodProxy 方法代理对象
*/
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("调用方法:" + method);
//可以调用MethodProxy的invokeSuper调用被代理类的方法
Object result = methodProxy.invokeSuper(o, objects);
return result;
}
});
//4.获取代理对象,调用enhancer.create方法获取代理对象,这个方法返回的是Object类型的,需要强转一下
Service1 proxy = (Service1) enhancer.create();
//5.调用代理对象的方法
proxy.m1();
proxy.m2();
}案例2:拦截所有方法(MethodInterceptor)
public class Service2 {
public void m1() {
System.out.println("我是m1方法");
this.m2();
}
public void m2() {
System.out.println("我是m2方法");
}
}@Test
public void test2() {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Service2.class);
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("调用方法:" + method);
Object result = methodProxy.invokeSuper(o, objects);
return result;
}
});
Service2 proxy = (Service2) enhancer.create();
proxy.m1();
}注意上面的代码,只调用了m1方法,看一下输出效果:
调用方法:public void com.javacode2018.lesson001.demo17.Service2.m1() 我是m1方法 调用方法:public void com.javacode2018.lesson001.demo17.Service2.m2() 我是m2方法
案例3:拦截所有方法并返回固定值(FixedValue)
enhancer.setCallback(new FixedValue() {
@Override
public Object loadObject() throws Exception {
return "路人甲";
}
});例如
public class Service3 {
public String m1() {
System.out.println("我是m1方法");
return "hello:m1";
}
public String m2() {
System.out.println("我是m2方法");
return "hello:m2";
}
}对用的测试用例:
@Test
public void test3() {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Service3.class);
enhancer.setCallback(new FixedValue() {
@Override
public Object loadObject() throws Exception {
return "路人甲";
}
});
Service3 proxy = (Service3) enhancer.create();
System.out.println(proxy.m1());
System.out.println(proxy.m2());
System.out.println(proxy.toString());
}运行输出
路人甲 路人甲 路人甲
案例4:直接放行,不做任何操作(NoOp.INSTANCE)
@Test
public void test6() {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Service3.class);
enhancer.setCallback(NoOp.INSTANCE);
Service3 proxy = (Service3) enhancer.create();
System.out.println(proxy.m1());
System.out.println(proxy.m2());
}运行结果
我是m1方法 hello:m1 我是m2方法 hello:m2
案例5:不同的方法使用不同的拦截器(CallbackFilter)
public class Service4 {
public void insert1() {
System.out.println("我是insert1");
}
public void insert2() {
System.out.println("我是insert2");
}
public String get1() {
System.out.println("我是get1");
return "get1";
}
public String get2() {
System.out.println("我是get2");
return "get2";
}
}@Test
public void test4() {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Service4.class);
//创建2个Callback
Callback[] callbacks = {
//这个用来拦截所有insert开头的方法
new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[]
objects, MethodProxy methodProxy) throws Throwable {
long starTime = System.nanoTime();
Object result = methodProxy.invokeSuper(o, objects);
long endTime = System.nanoTime();
System.out.println(method + ",耗时(纳秒):" + (endTime - starTime));
return result;
}
},
//下面这个用来拦截所有get开头的方法,返回固定值的
new FixedValue() {
@Override
public Object loadObject() throws Exception {
return "路人甲Java";
}
}
};
enhancer.setCallbackFilter(new CallbackFilter() {
@Override
public int accept(Method method) {
return 0;
}
});
//调用enhancer的setCallbacks传递Callback数组
enhancer.setCallbacks(callbacks);
/**
* 设置过滤器CallbackFilter
* CallbackFilter用来判断调用方法的时候使用callbacks数组中的哪个Callback来处理当前方法
* 返回的是callbacks数组的下标
*/
enhancer.setCallbackFilter(new CallbackFilter() {
@Override
public int accept(Method method) {
//获取当前调用的方法的名称
String methodName = method.getName();
/**
* 方法名称以insert开头,
* 返回callbacks中的第1个Callback对象来处理当前方法,
* 否则使用第二个Callback处理被调用的方法
*/
return methodName.startsWith("insert") ? 0 : 1;
}
});
Service4 proxy = (Service4) enhancer.create();
System.out.println("---------------");
proxy.insert1();
System.out.println("---------------");
proxy.insert2();
System.out.println("---------------");
System.out.println(proxy.get1());
System.out.println("---------------");
System.out.println(proxy.get2());
}运行结果
--------------- 我是insert1 public void com.javacode2018.lesson001.demo17.Service4.insert1(),耗时(纳秒):15396100 --------------- 我是insert2 public void com.javacode2018.lesson001.demo17.Service4.insert2(),耗时(纳秒):66200 --------------- 路人甲Java --------------- 路人甲Java
案例6:对案例5的优化(CallbackHelper)
@Test
public void test5() {
Enhancer enhancer = new Enhancer();
//创建2个Callback
Callback costTimeCallback = (MethodInterceptor) (Object o, Method method, Object[] objects, MethodProxy methodProxy) -> {
long starTime = System.nanoTime();
Object result = methodProxy.invokeSuper(o, objects);
long endTime = System.nanoTime();
System.out.println(method + ",耗时(纳秒):" + (endTime - starTime));
return result;
};
//下面这个用来拦截所有get开头的方法,返回固定值的
Callback fixdValueCallback = (FixedValue) () -> "路人甲Java";
CallbackHelper callbackHelper = new CallbackHelper(Service4.class, null) {
@Override
protected Object getCallback(Method method) {
return method.getName().startsWith("insert") ? costTimeCallback :
fixdValueCallback;
}
};
enhancer.setSuperclass(Service4.class);
//调用enhancer的setCallbacks传递Callback数组
enhancer.setCallbacks(callbackHelper.getCallbacks());
//设置CallbackFilter,用来判断某个方法具体走哪个Callback
enhancer.setCallbackFilter(callbackHelper);
Service4 proxy = (Service4) enhancer.create();
System.out.println("---------------");
proxy.insert1();
System.out.println("---------------");
proxy.insert2();
System.out.println("---------------");
System.out.println(proxy.get1());
System.out.println("---------------");
System.out.println(proxy.get2());
}运行结果
--------------- 我是insert1 public void com.javacode2018.lesson001.demo17.Service4.insert1(),耗时(纳秒):9777500 --------------- 我是insert2 public void com.javacode2018.lesson001.demo17.Service4.insert2(),耗时(纳秒):50600 --------------- 路人甲Java --------------- 路人甲Java
案例7:实现通用的统计任意类方法耗时代理类
public class CostTimeProxy implements MethodInterceptor {
//目标对象
private Object target;
public CostTimeProxy(Object target) {
this.target = target;
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
long starTime = System.nanoTime();
//调用被代理对象(即target)的方法,获取结果
Object result = method.invoke(target, objects);
long endTime = System.nanoTime();
System.out.println(method + ",耗时(纳秒):" + (endTime - starTime));
return result;
}
/**
* 创建任意类的代理对象
*
* @param target
* @param <T>
* @return
*/
public static <T> T createProxy(T target) {
CostTimeProxy costTimeProxy = new CostTimeProxy(target);
Enhancer enhancer = new Enhancer();
enhancer.setCallback(costTimeProxy);
enhancer.setSuperclass(target.getClass());
return (T) enhancer.create();
}
}使用非常简单,来个测试用例,如下:
@Test
public void test7() {
//创建Service1代理
Service1 service1 = CostTimeProxy.createProxy(new Service1());
service1.m1();
//创建Service3代理
Service3 service3 = CostTimeProxy.createProxy(new Service3());
System.out.println(service3.m1());
}运行结果
我是m1方法 public void com.javacode2018.lesson001.demo17.Service1.m1(),耗时(纳秒):53200 我是m1方法 public java.lang.String com.javacode2018.lesson001.demo17.Service3.m1(),耗时(纳秒):49200 hello:m1
十五、深入理解java注解
1、定义注解
public @interface MyAnnotation {}注解中定义参数
public @interface 注解名称{
[public] 参数类型 参数名称1() [default 参数默认值];
[public] 参数类型 参数名称2() [default 参数默认值];
[public] 参数类型 参数名称n() [default 参数默认值];
}访问修饰符必须为public,不写默认为public。
元素的类型只能是基本数据类型、String、Class、枚举类型、注解类型(体现了注解的嵌套效果)以及上述类型的一位数组。
该元素的名称一般定义为名词,如果注解中只有一个元素,请把名字起为value(后面使用会带来便利操作)。
参数名称后面的 () 不是定义方法参数的地方,也不能在括号中定义任何参数,仅仅只是一个特殊的语法。
default 代表默认值,值必须和第2点定义的类型一致。
如果没有默认值,代表后续使用注解时必须给该类型元素赋值。
2、指定注解的使用范围:@Target
@Target(value = {ElementType.TYPE,ElementType.METHOD})
public @interface MyAnnotation {
}看一下 @Target 源码
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
ElementType[] value();
}有一个参数value,是ElementType类型的一个数组,再来看一下 ElementType ,是个枚举,源码如下:
package java.lang.annotation;
/*注解的使用范围*/
public enum ElementType {
/*类、接口、枚举、注解上面*/
TYPE,
/*字段上*/
FIELD,
/*方法上*/
METHOD,
/*方法的参数上*/
PARAMETER,
/*构造函数上*/
CONSTRUCTOR,
/*本地变量上*/
LOCAL_VARIABLE,
/*注解上*/
ANNOTATION_TYPE,
/*包上*/
PACKAGE,
/*类型参数上*/
TYPE_PARAMETER,
/*类型名称上*/
TYPE_USE
}3、指定注解的保留策略:@Retention
源码阶段。
源码被编译为字节码之后变成class文件。
字节码被虚拟机加载然后运行。
@Retention(RetentionPolicy.SOURCE)
public @interface MyAnnotation {
}上面指定了 MyAnnotation 只存在于源码阶段,后面的2个阶段都会丢失。
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
RetentionPolicy value();
}有一个value参数,类型为RetentionPolicy枚举,如下:
public enum RetentionPolicy {
/*注解只保留在源码中,编译为字节码之后就丢失了,也就是class文件中就不存在了*/
SOURCE,
/*注解只保留在源码和字节码中,运行阶段会丢失*/
CLASS,
/*源码、字节码、运行期间都存在*/
RUNTIME
}4、为参数指定默认值
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Ann5 {
String[] name() default {"路人甲java", "spring系列"};
int[] score() default 1;
int age() default 30;
String address();
}5、注解信息的获取:AnnotatedElement
Package:用来表示包的信息。
Class:用来表示类的信息。
Constructor:用来表示构造方法信息。
Field:用来表示类中属性信息。
Method:用来表示方法信息。
Parameter:用来表示方法参数信息。
TypeVariable:用来表示类型变量信息,如:类上定义的泛型类型变量,方法上面定义的泛型类型变量。
6、AnnotatedElement常用方法
// 该元素如果存在指定类型的注解,则返回这些注解,否则返回 null。 <A extends Annotation> getAnnotation(Class<A> annotationClass); // 返回此元素上存在的所有注解,包括从父类继承的注解 Annotation[] getAnnotations(); // 如果指定类型的注解存在于此元素上,则返回true,否则返回 false boolean isAnnotationPresent(Class<?extends Annotation> annotationClass); // 返回直接存在于此元素上的所有注解,注意,不包括父类的注解,调用者可以随意修改返回的数组;这不会对其他调用者返回的数组产生任何影响,没有则返回长度为0的数组 Annotation[] getDeclaredAnnotations();
7、案例
@Target({ElementType.PACKAGE,
ElementType.TYPE,
ElementType.FIELD,
ElementType.CONSTRUCTOR,
ElementType.METHOD,
ElementType.PARAMETER,
ElementType.TYPE_PARAMETER,
ElementType.TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Ann11 {
String value();
}
@Target({ElementType.PACKAGE,
ElementType.TYPE,
ElementType.FIELD,
ElementType.CONSTRUCTOR,
ElementType.METHOD,
ElementType.PARAMETER,
ElementType.TYPE_PARAMETER,
ElementType.TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Ann11_0 {
int value();
}
@Ann11("用在了类上")
@Ann11_0(0)
public class UseAnnotation11<@Ann11("用在了类变量类型V1上") @Ann11_0(1) V1, @Ann11("用在了类变量类型V2上") @Ann11_0(2) V2> {
@Ann11("用在了字段上")
@Ann11_0(3)
private String name;
private Map<@Ann11("用在了泛型类型上,String") @Ann11_0(4) String, @Ann11("用在了泛型类型上,Integer") @Ann11_0(5) Integer> map;
@Ann11("用在了构造方法上")
@Ann11_0(6)
public UseAnnotation11() {
this.name = name;
}
@Ann11("用在了返回值上")
@Ann11_0(7)
public String m1(@Ann11("用在了参数上") @Ann11_0(8) String name) {
return null;
}
}解析类上的注解
// 解析类上的注解
for (Annotation annotation : UseAnnotation11.class.getAnnotations()) {
System.out.println(annotation);
}解析类上的类型变量
UseAnnotation11<@Ann11("用在了类变量类型V1上") @Ann11_0(1) V1, @Ann11("用在了类变量类型V2上") @Ann11_0(2) V2>// 解析类上的类型变量
TypeVariable<Class<UseAnnotation11>>[] typeParameters = UseAnnotation11.class.getTypeParameters();
for (TypeVariable<Class<UseAnnotation11>> typeParameter : typeParameters) {
System.out.println(typeParameter.getName() + "变量类型注解信息:");
Annotation[] annotations = typeParameter.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println(annotation);
}
}解析字段name上的注解
// 解析字段name上的注解
Field nameField = UseAnnotation11.class.getDeclaredField("name");
for (Annotation annotation : nameField.getAnnotations()) {
System.out.println(annotation);
}解析泛型字段map上的注解
// 解析泛型字段map上的注解
Field field = UseAnnotation11.class.getDeclaredField("map");
Type genericType = field.getGenericType();
Type[] actualTypeArguments = ((ParameterizedType) genericType).getActualTypeArguments();
AnnotatedType annotatedType = field.getAnnotatedType();
AnnotatedType[] annotatedActualTypeArguments = ((AnnotatedParameterizedType) annotatedType).getAnnotatedActualTypeArguments();
int i = 0;
for (AnnotatedType actualTypeArgument : annotatedActualTypeArguments) {
Type actualTypeArgument1 = actualTypeArguments[i++];
System.out.println(actualTypeArgument1.getTypeName() + "类型上的注解如下:");
for (Annotation annotation : actualTypeArgument.getAnnotations()) {
System.out.println(annotation);
}
}解析构造函数上的注解
// 解析构造函数上的注解
Constructor<?> constructor = UseAnnotation11.class.getConstructors()[0];
for (Annotation annotation : constructor.getAnnotations()) {
System.out.println(annotation);
}解析m1方法上的注解
// 解析m1函数上的注解
Method method = UseAnnotation11.class.getMethod("m1", String.class);
for (Annotation annotation : method.getAnnotations()) {
System.out.println(annotation);
}解析m1方法参数注解
// 解析m1方法参数注解
method = UseAnnotation11.class.getMethod("m1", String.class);
for (Parameter parameter : method.getParameters()) {
System.out.println(String.format("参数%s上的注解如下:", parameter.getName()));
for (Annotation annotation : parameter.getAnnotations()) {
System.out.println(annotation);
}
}上面参数名称为arg0,如果想让参数名称和源码中真实名称一致,操作如下:
如果你编译这个class的时候没有添加参数–parameters,运行的时候你会得到这个结果:Parameter: arg0 编译的时候添加了–parameters参数的话,运行结果会不一样:Parameter: args 对于有经验的Maven使用者,–parameters参数可以添加到maven-compiler-plugin的配置部分: <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.1</version> <configuration> <compilerArgument>-parameters</compilerArgument> <source>1.8</source> <target>1.8</target> </configuration> </plugin>
8、@Inherit:实现类之间的注解继承
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Inherited {
}public class InheritAnnotationTest {
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@interface A1{ //@1
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@interface A2{ //@2
}
@A1 //@3
interface I1{}
@A2 //@4
static class C1{}
static class C2 extends C1 implements I1{} //@5
public static void main(String[] args) {
for (Annotation annotation : C2.class.getAnnotations()) { //@6
System.out.println(annotation);
}
}
}@com.javacode2018.lesson001.demo18.InheritAnnotationTest$A2()
9、@Repeatable重复使用注解
先定义容器注解
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.FIELD})
@interface Ann12s {
Ann12[] value(); //@1
}为注解指定容器
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.FIELD})
@Repeatable(Ann12s.class)//@2
@interface Ann12 {
String name();
}使用注解
重复使用注解,如下面的类上重复使用@Ann12注解。
通过容器注解来使用更多个注解,如下面的字段v1上使用@Ann12s容器注解。
@Ann12(name = "路人甲Java")
@Ann12(name = "Spring系列")
public class UseAnnotation12 {
@Ann12s({@Ann12(name = "Java高并发系列,见公众号"),@Ann12(name = "mysql高手系列,见公众号")})
private String v1;
}Annotation[] annotations = UseAnnotation12.class.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println(annotation);
}
System.out.println("-------------");
Field v1 = UseAnnotation12.class.getDeclaredField("v1");
Annotation[] declaredAnnotations = v1.getDeclaredAnnotations();
for (Annotation declaredAnnotation : declaredAnnotations) {
System.out.println(declaredAnnotation);
}参考:路人甲-Spring系列
版权声明
非特殊说明,本文由Zender原创或收集发布,欢迎转载。
ZENDER

发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。