Neden @Autowired kullanılması önerilmiyor? Constructor Injection Avantajları
Bu yazıda neden Autowired anotasyonu kullanılması önerilmiyor konusunu aktarmaya çalışacağım. Mülakatlarda sıkça karşılaşılan bu soruyu olabildiğince yalın bir şekilde ve örnekler üzerinden açıklamaya çalışacağım.
Umarım karşınıza çıktığında güzel bir şekilde cevaplamanıza vesile olabilirim :)
Bildiğiniz gibi Autowired anotasyonu bağımlılık inject etmek için kullanılıyor. Aşağıda kullanım örneğini bulabilirsiniz.
İsterseniz bu noktada ilk olarak dependency injection tekniğini konuşalım. Ardından Spring Framework’de bunun ne şekilde uygulandığına değinelim. Daha sonra bir setter injection yöntemi olan Autowired anotasyonunun tavsiye edilmeme sebeplerini inceleyelim.
Spring IOC Container
Spring Framework, Program to Interface yaklaşımını benimser. Bu yaklaşımda sınıflar arasındaki bağımlılıklar interfaceler ve abstract sınıflar aracılığıyla sağlanır.
Kelime anlamı kontrolün tersine çevrilmesi olan IOC(Inversion of Control) modülerliği sağlayan bir prensip. Kontrolü geliştiriciden alıp başka bir aktöre mesela framework’e teslim ediyor. Kontrolü framework’e teslim ettiğimizde loosely coupling(gevşek bağlı) sağlıyoruz. Yani bir nesneyi yaratırken bağımlılıkları minimuma indiriyoruz.
Şimdi gelelim Spring Framework’e…
Biz geliştiriciler olarak java nesnelerini yaratmaktan sorumluyuz. İşte bu sorumluluk bizden alınıp Spring IOC Container’a geçiyor. Application context olarak da isimlendirilen Spring IOC Container, java nesnelerinin ihtiyaç duyulduğunda uygun parametre ve konfigürasyonlarla oluşturulmasını sağlıyor.
- Nesne bağımlılıkların sağlandığı concrete sınıfları bilmez.
IOC’yi uygulamanın aşağıdaki resimde göreceğiniz gibi birçok yolu var. Dependency injection’da bunlardan birisi.
Dependency Injection
Yazılım mühendisliğinde bir nesne vasıtasıyla başka bir nesnenin bağımlılıklarının sağlandığı bir tekniktir.
Spring IOC Container’dan talep ettiğimiz onun factory metodu üzerinden üretilmiş sınıfın alınıp uygun bağımlılık olarak runtime’da inject edilmesine DI(dependency injection) deniyor.
Dependency injection 3 farklı yöntemle yapılmaktadır.
- Constructor Injection (tavsiye edilen yöntem)
- Setter Injection (Property Injection)
- Method Injection
Yazının konusu ve tavsiye edilen yöntem ise constructor injection. Aşağıda kullanım örneğini bulabilirsiniz.
Neden Constructor Injection ?
- Testability — NullPointer Exception’ı önleyerek testlerde hata alınması engeller. Testte, mock nesneleri constructora aktarmak kolaydır.
Eğer Autowired kullanmış olsaydık testte aşağıdaki hatayı alıyor olacaktık. Bu yüzden Autowired kullanılması önerilmiyor.
- Safety — Spring’i zorunlu bağımlılıkları sağlamaya zorlar. Oluşturulan nesnelerin constructiondan sonra valid durumda olduğundan emin oluruz.
- Readability — Constructor’a parametre olarak geçilen bağımlılıklar, zorunlu bağımlılıklardır. Property yada setter injection yöntemiyle sağlanan bağımlılıklar ise opsiyoneldir.
Son olarak Spring ekibinin bu konudaki açıklamasını okumak isteyenler için bırakıyorum.
Constructor-based or setter-based DI?
Since you can mix constructor-based and setter-based DI, it is a good rule of thumb to use constructors for mandatory dependencies and setter methods or configuration methods for optional dependencies. Note that use of the @Required annotation on a setter method can be used to make the property be a required dependency; however, constructor injection with programmatic validation of arguments is preferable.
The Spring team generally advocates constructor injection, as it lets you implement application components as immutable objects and ensures that required dependencies are not
null
. Furthermore, constructor-injected components are always returned to the client (calling) code in a fully initialized state. As a side note, a large number of constructor arguments is a bad code smell, implying that the class likely has too many responsibilities and should be refactored to better address proper separation of concerns.Setter injection should primarily only be used for optional dependencies that can be assigned reasonable default values within the class. Otherwise, not-null checks must be performed everywhere the code uses the dependency. One benefit of setter injection is that setter methods make objects of that class amenable to reconfiguration or re-injection later. Management through JMX MBeans is therefore a compelling use case for setter injection.
Use the DI style that makes the most sense for a particular class. Sometimes, when dealing with third-party classes for which you do not have the source, the choice is made for you. For example, if a third-party class does not expose any setter methods, then constructor injection may be the only available form of DI.
Umarım faydalı olmuştur sizin için. Kaynak kodlara şu repodan ulaşabilirsiniz.
Keep coding ! 🚀