이 기사는 원래 MaNong.com – Sun Tenghao에서 번역되었습니다. 재인쇄하려면 기사 끝에 있는 재인쇄 요구 사항을 읽어보세요. 유료 기부 계획에 참여하신 것을 환영합니다!
Java 1.5에 주석이 도입되었을 때 엔터프라이즈 개발자는 EJB 및 기타 엔터프라이즈 제품의 개발을 단순화하기를 기대하는 것이 컸습니다. 같은 기간의 Simplifying Enterprise Java Development with EJB 3.0에 대한 기사를 살펴볼 수 있습니다.
그러나 그 이후로 Java 기업에서 주석을 사용하면 예상치 못한 결과와 부작용이 발생했으며 그 중 일부는 오늘날에도 발견되지 않았습니다. 다행스럽게도 모든 부작용이 눈에 띄지 않는 것은 아닙니다. 몇 가지 예를 살펴보면 "왜 Java 주석이 필요한가요?"라는 제목의 귀중한 의견이 많이 있으며 "주석은 나쁜가요?"라는 글이 있습니다. ” “주석…좋은가요, 나쁜가요, 아니면 나쁜가요?”
위의 많은 토론에는 중요한 사항이 포함되어 있지만 모든 주석이 동일한 것은 아닙니다. 동일합니다.
주석에는 두 가지 유형이 있으며 차이점은 런타임 중에 프로그램에 영향을 미치는지 여부에 있습니다. 먼저, 런타임 시 코드에 아무런 영향을 주지 않는 무해한 것에 대해 이야기해 보겠습니다. 다른 하나는 런타임 동작을 수정하는 유해한 것입니다. 무해한 주석에는 @Deprecated, @Override, @SuppressWarnings 등이 포함됩니다. 유해한 주석에는 @Entity, @Table, @PostConstruct, @ApplicationScoped 등이 포함됩니다.
무해한 주석 중에 매우 유용한 작은 주석 집합이 있습니다. 일부는 컴파일 중에 오류 잡기(정적 검사)를 제공하거나 안전 보장을 제공합니다. 유용한 주석으로는 @Override, (Checker Framework)의 @NonNull/@Nullable 등이 있습니다.
몇 가지 유해한 주석을 정의했는데 왜 이러한 주석을 사용하지 말아야 합니까?
@PostConstruct 메소드가 있는 표준 Java 데이터 클래스를 상상해 보세요. 이 주석은 객체가 생성된 후 주석이 달린 메서드를 호출해야 함을 나타냅니다. 이 기능은 JVM에서 처리되지 않으므로 Date 클래스는 의미상 아무 것도 수행하지 않고 암시적으로 알 수 없는 프레임과 컨테이너를 얻습니다. 이 코드가 어떤 컨테이너에서도 실행되지 않고 JVM에서만 실행된다면 어떻게 될까요? 이 주석은 이 클래스의 재사용성을 크게 줄입니다. 또한 Date를 사용하는 곳에서 단위 테스트를 수행하는 것은 악몽이 됩니다. 왜냐하면 사후 구성이 매번 올바르게 바인딩되었는지 확인해야 하고 호환 가능한 컨테이너를 시뮬레이션해야 하기 때문입니다. 이것은 약간 우스꽝스럽습니다. Date 클래스를 실행하려면 컨테이너가 필요하지만 이는 실제로 클래스, 메소드 및 매개변수에 대한 주석의 해로운 영향입니다.
비즈니스 로직이 종종 복잡하고 단순한 Date 클래스보다 더 많은 종속성과 관계가 필요하다는 것은 부인할 수 없습니다. 그러나 불필요한 종속성이나 제약 조건을 클래스에 명시적으로나 암시적으로 추가할 이유는 없습니다. 유해한 주석은 바로 종속성 및 제약 조건입니다.
안타깝게도 Java Enterprise 5에서는 대규모로 유해한 주장이 합법화되고 있습니다. 엔터프라이즈 API의 초기 사용성 문제를 해결하기 위해 주석을 사용하여 시스템의 중복되고 사용하기 어려운 부분을 숨겼습니다. 새로운 JEE 5는 '가벼움'과 '단순함'이라는 평가를 받았으며 표면적으로도 그렇게 보입니다. 그러나 사소하지만 결정적인 오용이 확산되었습니다.
@Stateless public class DocumentRepository { public Document getDocument(String title) { ... } ... }
Stateless EJB를 얻으려면 클래스에 @Stateless 주석을 선언하기만 하면 됩니다. 실제로 이 클래스를 작성하려면 몇 번의 클릭만으로 충분하지만 이 클래스의 유해한 주석은 수백 페이지의 문서와 연결되어 있으며 메가바이트 애플리케이션 서버에서만 실행된다는 점에 유의하세요. 이것을 어떻게 "경량"이라고 부를 수 있습니까? 따라서 이 주석은 실제로 작성해야 하는 Java 코드에 대한 자리 표시자일 뿐이며 코드는 여전히 어떤 형태로 존재해야 합니다. 이제는 주석 아래에 숨겨져 있습니다.
안타깝게도 이 해결 방법은 패턴으로 알려져 있으며 현재 JPA, CDI, Common Annotations, JAXB 등 유해한 주석이 널리 배포되어 있습니다.
주석은 개발 환경으로 사용되는 경우가 많기 때문에 유해한 주석이 단일 책임 원칙(Single Responsibility 원칙)으로 취급되는 경우도 있습니다. 또는 우려 사항 분리를 위한 모범 사례.
다음 CDI 예를 고려해 보겠습니다.
@ApplicationScoped public class DocumentFormatter { ... }
위의 주석에서는 이 클래스가 CDI Bean이어야 한다고 설명합니다. CDI 및 애플리케이션당 하나의 인스턴스만 보장합니다.
이 메시지는 이 카테고리에 속하지 않습니다. 이 서비스는 기능적으로(어떤 방식으로든) 현재 애플리케이션에서의 역할에 영향을 미치지 않습니다. 여기에는 두 가지 분명한 우려 사항이 있습니다.
JPA의 간단한 예:
@Entity @Table("PERSON") public class Person { ... }
问题在于这种类往往是”领域对象(domain objects)”,它们直接将领域模型持久化。更糟的是,数据传送对象(DTO)用来在对象之间传送数据,使得整个构造变得脆弱,因为对象间耦合过于紧密。不管怎样,这是一种错误的方式。
所有的这些附加的功能和(或)信息应该从这些类中分离出来,但是它们却悄悄混在一起,因为它们”只不过”是注解。
注解有时会传染其他对象。回顾上面那个CDI Bean。每个使用它的对象,每个依赖它的对象现在都拥有一个CDI注解,否则依赖关系树就不会构建成功。
@Entity注解也一样。因为对象之间的关系,其他对象也通过注解持久化,很快所有的持久化对象都会有这个注解。我们无法使用原生的第三方对象(除非序列化或包装它们),我们无法使用其他持久化机制(比如用NoSQL DB存放对象)。
这些注解使得这些对象无法复用。它们只能在一个严格的、受控制的、不透明的环境中使用,不能和任何东西整合。
是XML吗?当然不是,至少对于上面的例子来说不是。
Spring框架使用配置来管理对象,因此可以用XML当做配置文件。然而,是否某个依赖需要在运行期改变,而不通过重新编译?如果不需要,那么很难说配置应该用另一门语言来表示,尤其重构困难、测试困难、管理需要特殊工具。
真正的替代品当然是好的Java代码,正确封装并解耦的。是的,用代码来管理对象,尽管有时被当做样板(boilerplate),但并不算糟糕。它带来一些好处,比如让代码可读、可调试、可重构。只有那些长片的、复杂的、冗余的样板是糟糕的,比如“关于EJB 2.0”。但是解决方案并不是摆脱所有的样板或用另一种语言隐藏样板,而是简单干净的架构,直接而不多余的信息,简单并合适的方式来面向对象。
这也适用于JPA、Spring和其他东西。误用注解来表示功能会发生Stcakoverflow上这个问题“Arguments Against Annotations”,为什么不用已有的工具呢:比如Java语言本身和编译器,来解决这类问题,面向对象和软件最佳实践。
如果注解在代码运行期加上了额外功能和约束,那它是有害的。这很糟糕,因为它隐藏了类或方法的切面,使之难懂、难复用、难重构、难测试。
不幸的是Java Enterprise不理睬Java开发者社区中发对注解的声音。所以企业级Java和其他”官方”框架更不可能重视这类问题。
至少我们可以持续关注有害的注解,如果可能尽量避免使用,编写新的框架和软件替换掉注解,不会出现有害注解所带来的问题。
以上就是Java中万恶的注解 的内容,更多相关内容请关注PHP中文网(m.sbmmt.com)!