由Spring的事务不支持静态方法所联想到的。。。

由Spring的事务不支持静态方法所联想到的。。。

一、Spring的@Transactional不支持static方法

正确的编程习惯可以帮你避免很多陷阱,让程序远离莫名的异常和崩溃,也让测试和运维变得轻松不少。好处虽多,却有一个坏处,在于你可能不容易对一些司空见惯的现象产生一探究竟的欲望。有些讽刺的是,在开发过程中遇到的很多异常反而会提升你的技术实力。
正如使用Spring,特别是Spring MVC时,如果遵循正确的编程规范,那你是不会试图将一个static方法标记为@Transactional的。并且一般情况下你的Service类里面也不应该有static方法。也因此你可能不会知道,这么做只会让你得到一个的异常——Spring的@Transactional不支持static方法。

二、为什么@Transactional不支持static方法?

Spring的注解是基于Spring AOP的,而Spring AOP则通过JDK的动态代理(需要接口)或者CGLib的动态代理(无需接口)来实现拦截的功能。而无论JDK还是CGlib都无法对静态方法提供代理。原因在于 静态方法是类级别的,调用需要知道类信息,而类信息在编译器就已经知道了,并不支持在运行期的动态绑定。
出于直觉,你可能也会认为java的interface应该不支持静态方法吧,毕竟interface只是用来提供接口定义的,由子类提供各自的实现,静态的方法没有任何意义。

三、什么?接口里面也可以实现静态方法?

确切的说是从JDK8开始,你可以在interface里面写static方法(以及default方法)了。你可能会问一些为什么,比如为什么JDK8要提供这种支持,为什么JDK8之前没有提供这种支持等等。答案是没有为什么,至少没有明确的原因。早在jdk7的开发时,某些人提出可以在interface里面定义static方法,然后在jdk8时就实现了这个功能。所以下面的代码在jdk8时没有任何问题:

public interface Test {

    static void test() {
        System.out.println("i'm a static method!");
    }
}

这里有两点需要特别注意:
1. 接口里的static方法不能在子类中访问。
2. 类里面的static方法会被子类继承,因此可以被子类访问,但是不能被override。也就是说如果你在子类中实现了同名的static方法,并且试图加上@Override注解,编译器会提示你超类里面没有方法。去掉@Override注解则可以正常编译运行,因为这时你实际上隐藏了(而非覆写了)父类中的同名static方法。

具体示例如下:

  1. 接口的static方法
public interface Test {
   
    static void test() {
        System.out.println("i'm a static method!");
    }
}
public class TestImpl implements Test {
   

    public static void main(String[] args) {
        TestImpl t = new TestImpl();
        Test.test(); // 运行正常
        t.test(); //编译失败,提示没有这个方法
    }
  1. 类的static方法
    public class Test1 {
   
        public static void test() {
            System.out.println("i am Test1.test()");
        }
        public static void test2(){
            System.out.println("i am Test1.test2()");
        }
    }
    public class Test2 extends Test1 {
   
        @Override // 编译错误,去掉以后就没有问题
        public static void test() { 
            System.out.println("i am Test2.test()");
        }
    }
    // 去掉上面的@Override后运行结果如下:
    public class Main {
   
        public static void main(String[] args) {
            Test1.test(); //打印 i am Test1.test()
            Test2.test(); //打印 i am Test2.test()
            Test1.test2();//打印 i am Test1.test2()
            Test2.test2();//打印 i am Test1.test2()
        }
    }

参考链接

http://stackoverflow.com/questions/23569732/transactional-with-static-method
http://stackoverflow.com/questions/512877/why-cant-i-define-a-static-method-in-a-java-interface
http://stackoverflow.com/questions/16617408/why-doesnt-the-compiler-complain-when-i-try-to-override-a-static-method

「点点赞赏,手留余香」

    还没有人赞赏,快来当第一个赞赏的人吧!
0 条回复 A 作者 M 管理员
    所有的伟大,都源于一个勇敢的开始!
欢迎您,新朋友,感谢参与互动!欢迎您 {{author}},您在本站有{{commentsCount}}条评论