【Java】spring中某方法@Transactional 设置了propogation后,能在方法中修改方法的事务传播属性吗?
譬如
@Transactional(propagation = Propagation.REQUIRES_NEW))void doSomething(){}
@Transactional
void caller(){
//修改doSomething的事务传播属性为Propagation.REQUIRED
doSomething();
}
回答
题主你好,这个问题的回答,我觉得理论上可以,为啥说是理论呢
因为你的最终目标可能应该是可以在运行时动态改变注解中的属性值
所以这里涉及两个问题
Java
本身语法层面上是否支持可以修改- 修改值之后,新值是否能生效
第一个问题是纯语法问题,先不提,这里先要说明哈第二个问题,因为Transactional
注解是Spring
的提供的配置注解,所以就算修改了Transactional
中的属性值,运行时应该不是采用实时Transactional
注解的新值,应该这类配置都是在Spring
初始化时,就另外对象包装存储起来的,类似缓存起来,所以这点我没有深究,但是理论上改完Spring
缓存值应该最终能达到目的。除非完全保护起来不允许修改,但是这个保护机制是Spring
提供,并不涉及第一个问题
再来说说第一个问题,起初看到这个问题,我是这么想的,注解本身就是一个接口,而注解存在的地方其实就是这个接口的一个实现类,一个实例对象,所以换句话说其实就是改变实例对象的属性值,这个再怎么也应该可以做到,只是这些注解实例应该有一个地方存储,这个地方我之前没有了解过,但我觉得应该存在,最后我查找了一些资料了解了以下处理方式,仅供参考
假设我们一个类注解
@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)
public @interface ClassAnnotation {
String value() default "";
}
我们创建一个测试类TestClass
,然后给它加上这个注解ClassAnnotation
@ClassAnnotation("class test")public class TestClass{
}
平常我们在获取注解ClassAnnotation
时,其实一般都是这么做的
ClassAnnotation classAnnotation = TestClass.class.getAnnotation(ClassAnnotation.class);
但是我们获取出来classAnnotation
对象其实是一个代理对象
这里我们可以拿到这个代理类的InvocationHandler
类,然后InvocationHandler
中一个属性memberValues
,而这个memberValues
属性其实是一个map
,而这个map
就是存储的这个注解中定义的各种属性信息,包括属性名和值,key
是属性名,value
是属性值,因此只用修改对应的属性名的属性值即可
所以就可以写出这样一个工具方法changeAnnotationValue
/** *
* @param annotation 当前注解代理对象
* @param key 需要修改的注解的属性名
* @param newValue 需要修改的注解的属性新值
* @return
*/
public static Object changeAnnotationValue(Annotation annotation, String key, Object newValue){
Object handler = Proxy.getInvocationHandler(annotation);
Field f;
try {
f = handler.getClass().getDeclaredField("memberValues");
} catch (NoSuchFieldException | SecurityException e) {
throw new IllegalStateException(e);
}
f.setAccessible(true);
Map<String, Object> memberValues;
try {
memberValues = (Map<String, Object>) f.get(handler);
} catch (IllegalArgumentException | IllegalAccessException e) {
throw new IllegalStateException(e);
}
Object oldValue = memberValues.get(key);
if (oldValue == null || oldValue.getClass() != newValue.getClass()) {
throw new IllegalArgumentException();
}
memberValues.put(key,newValue);
return oldValue;
}
然后用这个方法,我们可以做一个测试
ClassAnnotation classAnnotation = TestClass.class.getAnnotation(ClassAnnotation.class);System.out.println("old ClassAnnotation = " + classAnnotation.value());
changeAnnotationValue(classAnnotation, "value", "another class annotation value");
System.out.println("modified ClassAnnotation = " + classAnnotation.value());
运行结果
当然方法类注解或者字段类注解同理
@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.METHOD)
public @interface MethodAnnotation {
String value() default "";
}
@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.FIELD)
public @interface FieldAnnotation {
String value() default "";
}
@ClassAnnotation("class test")public class TestClass{
@FieldAnnotation("field test")
public Object field;
@MethodAnnotation("method test")
public void method(){ }
public static void main(String[] args) throws Exception {
// 类注解
ClassAnnotation classAnnotation = TestClass.class.getAnnotation(ClassAnnotation.class);
System.out.println("old ClassAnnotation = " + classAnnotation.value());
changeAnnotationValue(classAnnotation, "value", "another class annotation value");
System.out.println("modified ClassAnnotation = " + classAnnotation.value());
// 字段注解
Field field = TestClass.class.getField("field");
FieldAnnotation fieldAnnotation = field.getAnnotation(FieldAnnotation.class);
System.out.println("old FieldAnnotation = " + fieldAnnotation.value());
changeAnnotationValue(fieldAnnotation, "value", "another field annotation value");
System.out.println("modified FieldAnnotation = " + fieldAnnotation.value());
// 方法注解
Method method = TestClass.class.getMethod("method");
MethodAnnotation methodAnnotation = method.getAnnotation(MethodAnnotation.class);
System.out.println("old MethodAnnotation = " + methodAnnotation.value());
changeAnnotationValue(methodAnnotation, "value", "another method annotation value");
System.out.println("modified MethodAnnotation = " + methodAnnotation.value());
}
}
以上就是语法层面的修改,Spring
层面上的修改,我没有细追,不过我觉得是可以的,我只是简单测试过RequestMapping
注解的method
属性,之前只支持GET
,后面改为只支持POST
,并不会生效,所以我觉得Transactional
注解应该也是类似,毕竟Spring
肯定需要统一管理这些注解配置,而不会去原值读取
如果题主最终找出解决方案,麻烦更新分享哈,我后面有空了也会去追哈源码看看,谢谢啦
不能...如果只是普通的修改一个方法的注解值的话可以通过反射办到
但是Spring实际上加载使用的是你原来类后生成的代理类 也就是说你得直接改他的代理类才行
但也不排除什么黑科技操作...不过以我的姿势水平来说是不能的
以上是 【Java】spring中某方法@Transactional 设置了propogation后,能在方法中修改方法的事务传播属性吗? 的全部内容, 来源链接: utcz.com/a/90450.html