คุณสามารถใช้ @Autowired กับเขตข้อมูลแบบคงที่ได้หรือไม่


คำตอบ:


122

ในระยะสั้นไม่มี คุณไม่สามารถอัตโนมัติหรือผูกสายฟิลด์คงที่ด้วยตนเองในฤดูใบไม้ผลิ คุณจะต้องเขียนตรรกะของคุณเองเพื่อทำสิ่งนี้


3
เมื่อคุณพบรหัสเก่าที่ทำสิ่งนี้มันเป็นรูปแบบการต่อต้าน เอียงหัวของคุณและหาวิธีที่ดีกว่าในการแก้ปัญหา คุณจะดีใจที่คุณทำ
Joseph Lust

2
นี้คำตอบยังเป็นประโยชน์ในฤดูใบไม้ผลิ@AutoWired
เควินเมเรดิ ธ

116
@Component("NewClass")
public class NewClass{
    private static SomeThing someThing;

    @Autowired
    public void setSomeThing(SomeThing someThing){
        NewClass.someThing = someThing;
    }
}

1
ความคิดใดที่ฉันสามารถใช้วิธีการนี้เมื่อเริ่มต้นพื้นที่เก็บข้อมูล?
kiedysktos

3
ข้อเสีย: ไม่มีการรับประกันที่someThingได้รับการเริ่มต้นถ้าเข้าถึงแบบคงที่: NewClass.staticMethodWhichUsesSomething();อาจโยน NPE ถ้าใช้ก่อนการเริ่มต้นแอป
Neeraj

คุณสามารถหลีกเลี่ยงคำเตือนได้Instance methods should not write to "static" fields (squid:S2696)หรือไม่?
7294900

@ user7294900: ปิดการใช้งานคำเตือนนี้เฉพาะกรณีนี้เท่านั้น
izogfif

@izogfif ยังคงมีปัญหาหากฉันเลือกวิธีนี้ในกรณีและคลาสที่กว้าง
user7294900

67

@Autowired สามารถใช้กับตัวตั้งค่าเพื่อให้คุณสามารถตั้งค่าตัวปรับเปลี่ยนฟิลด์แบบคงที่

ข้อเสนอแนะสุดท้ายเพียงข้อเดียว ... ไม่


54
ทำไมคุณไม่แนะนำให้ทำเช่นนี้?
Jon Lorusso

3
อืม .. ความรู้สึกของฉันเกี่ยวกับสาเหตุที่ไม่แนะนำคือเพราะอินสแตนซ์คงที่ในชั้นเรียนอยู่นอกเหนือการควบคุมของฤดูใบไม้ผลิ เมื่อฉีดเขตข้อมูลคงที่คือการอ้างอิงสำหรับทุกอินสแตนซ์ของวัตถุของคลาส (โดยรอบ) ที่สอดคล้องกัน แต่พฤติกรรมนี้อาจเป็นสิ่งที่คาดว่าจะเกิดขึ้นอย่างแน่นอนดังนั้นจึงอาจถูกมองว่าเป็นข้อผิดพลาดหรือคุณลักษณะ ...
matthaeus

1
ใช่ @matthaeus เป็นคุณลักษณะที่ฉันคาดหวังเมื่อต้องการเข้าถึง@Component public class SpringAppEnv{ public static Environment _env; @Autowired public void setEnv(Environment env) {_env = env;} }
org.springframework.core.env.Environment

@JonLorusso และทั้งหมดเนื่องจากเมื่อโหลดเดอร์คลาสโหลดค่าคงที่บริบท Spring ยังไม่จำเป็นต้องโหลด ดังนั้นตัวโหลดคลาสจะไม่ฉีดคลาสคงที่ในถั่วอย่างถูกต้องและจะล้มเหลว ตอบโดย Andrea T
Jeril Kuruvila

14

เริ่มส่วนประกอบที่เป็นอัตโนมัติในเมธอด @PostConstruct

@Component
public class TestClass {
   private static AutowiredTypeComponent component;

   @Autowired
   private AutowiredTypeComponent autowiredComponent;

   @PostConstruct
   private void init() {
      component = this.autowiredComponent;
   }

   public static void testMethod() {
      component.callTestMethod();
   }
}

คุณสามารถหลีกเลี่ยงคำเตือนได้Instance methods should not write to "static" fields (squid:S2696)หรือไม่?
7294900

คุณสามารถทำได้โดยตรงผ่านตัวสร้าง
gagarwa

5

สร้าง bean ที่คุณสามารถ autowire ซึ่งจะเริ่มต้นตัวแปรคงที่เป็นผลข้างเคียง


4

คุณสามารถบรรลุนี้โดยใช้สัญกรณ์ XMLMethodInvokingFactoryBeanและ สำหรับตัวอย่างดูที่นี่

private static StaticBean staticBean;

public void setStaticBean(StaticBean staticBean) {
   StaticBean.staticBean = staticBean;
}

คุณควรตั้งเป้าหมายที่จะใช้สปริงสปริงเนื่องจากเป็นวิธีที่แนะนำแต่มันไม่ได้เป็นไปได้เสมอเพราะฉันแน่ใจว่าคุณสามารถจินตนาการได้ว่าไม่ใช่ทุกสิ่งที่สามารถดึงออกมาจากสปริงคอนเทนเนอร์หรือคุณอาจจัดการกับระบบเดิม

การทดสอบหมายเหตุอาจทำได้ยากขึ้นด้วยวิธีนี้


2

ต้องการเพิ่มคำตอบว่าจะไม่สนใจฟิลด์การวางสายอัตโนมัติ (หรือค่าคงที่) แต่จะไม่สร้างข้อผิดพลาดใด ๆ :

@Autowired
private static String staticField = "staticValue";

1

คุณสามารถใช้ ApplicationContextAware

@Component
public class AppContext implements ApplicationContextAware{
    public static ApplicationContext applicationContext;

    public AppBeans(){
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}

แล้วก็

static ABean bean = AppContext.applicationContext.getBean("aBean",ABean.class);

0

ข้อจำกัดความรับผิดชอบนี่ไม่ใช่มาตรฐานและอาจเป็นวิธีที่ดีกว่าในการทำสิ่งนี้ ไม่มีคำตอบใดที่กล่าวถึงปัญหาของการเดินสายในเขตข้อมูลสาธารณะ

ฉันต้องการทำสามสิ่งให้สำเร็จ

  1. ใช้สปริงเป็น "Autowire" (ฉันใช้ @Value)
  2. เปิดเผยค่าคงที่สาธารณะ
  3. ป้องกันการดัดแปลง

วัตถุของฉันมีลักษณะเช่นนี้

private static String BRANCH = "testBranch";

@Value("${content.client.branch}")
public void finalSetBranch(String branch) {
    BRANCH = branch;
}

public static String BRANCH() {
    return BRANCH;
}

เราได้ตรวจสอบ 1 และ 2 แล้วตอนนี้เราจะป้องกันการโทรไปยัง setter ได้อย่างไรเนื่องจากเราไม่สามารถซ่อนมันได้

@Component
@Aspect
public class FinalAutowiredHelper {

@Before("finalMethods()")
public void beforeFinal(JoinPoint joinPoint) {
    throw new FinalAutowiredHelper().new ModifySudoFinalError("");
}

@Pointcut("execution(* com.free.content.client..*.finalSetBranch(..))")
public void finalMethods() {}


public class ModifySudoFinalError extends Error {
    private String msg;

    public ModifySudoFinalError(String msg) {
        this.msg = msg;
    }

    @Override
    public String getMessage() {
        return "Attempted modification of a final property: " + msg;
    }
}

กว้างยาวนี้จะห่อวิธีทั้งหมดที่เริ่มต้นด้วยขั้นสุดท้ายและโยนข้อผิดพลาดถ้าพวกเขาถูกเรียกว่า

ฉันไม่คิดว่ามันจะมีประโยชน์เป็นพิเศษ แต่ถ้าคุณเป็น ocd และอยากให้คุณแยกถั่วกับแครอทนี่เป็นวิธีหนึ่งที่จะทำได้อย่างปลอดภัย

สิ่งสำคัญ Spring ไม่เรียกลักษณะของคุณเมื่อเรียกใช้ฟังก์ชัน ทำให้เรื่องนี้ง่ายขึ้นแย่ไปกว่านั้นฉันก็หาตรรกะก่อนที่จะหามัน


-1
private static UserService userService = ApplicationContextHolder.getContext().getBean(UserService.class);

2
แม้ว่ารหัสนี้อาจแก้ปัญหาได้รวมถึงคำอธิบายว่าทำไมและวิธีแก้ปัญหานี้จะช่วยปรับปรุงคุณภาพการโพสต์ของคุณได้อย่างไรและอาจส่งผลให้คะแนนมากขึ้น จำไว้ว่าคุณกำลังตอบคำถามสำหรับผู้อ่านในอนาคตไม่ใช่เพียงแค่คนที่ถามตอนนี้ โปรดแก้ไขคำตอบของคุณเพื่อเพิ่มคำอธิบายและระบุข้อ จำกัด และสมมติฐานที่ใช้
เสียงบี๊บสองครั้ง

ฉันคิดว่าคำตอบนี้อาจไม่ต้องการคำอธิบายใด ๆ เลย
Chaklader Asfak Arefe
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.