Bu Sayfayı Paylaş:

Kavram

CDI - Contexts and Dependency Injection

Tanım: Java EE (Kurumsal Sürüm) içinde, farklı context ve ortamların (Web, EJB, JMS vb..) birbirine bağımlılıklarını esnek hale getiren ve basit bir şekilde yönetilmesini sağlayan sistem. Örneğin bir EJB, JSF'de kullanılan bir bean'e inject edilebilir.

İpucu

Tomcat ile CDI Kullanımı

Tomcat üzerinde CDI kullanmak istiyorsanız Weld kütüphanesini kullanabilirsiniz. Bunun için aşağıdakileri yapmanız gerekir.
Gerekli kütüphaneleri aşağıdaki gibi ekleyelim
<dependency>
	<groupId>javax.enterprise</groupId>
	<artifactId>cdi-api</artifactId>
	<version>1.2</version>
	<scope>provided</scope>
</dependency>
<dependency>
	<groupId>org.jboss.weld.servlet</groupId>
	<artifactId>weld-servlet</artifactId>
	<version>2.4.2.Final</version>
</dependency>
CDI API ve weld servlet kütüphanesi eklenmiştir.
Web.xml'e aşağıdaki gibi listener eklenir
<listener>
	<listener-class>org.jboss.weld.environment.servlet.Listener</listener-class>
</listener> 
Bean yönetimi için META-INF altına context.xml dosyası eklenir ve aşağıdakiler dosyaya yazılır:
<Context>
   <Resource name="BeanManager" 
      auth="Container"
      type="javax.enterprise.inject.spi.BeanManager"
      factory="org.jboss.weld.resources.ManagerObjectFactory"/>
</Context>
Ardından burada tanımlanan BeanManager web.xml'e eklenir
<resource-env-ref>
	<resource-env-ref-name>BeanManager</resource-env-ref-name>
	<resource-env-ref-type>javax.enterprise.inject.spi.BeanManager</resource-env-ref-type>
</resource-env-ref>
WEB-INF klasörüne içi boş da olsa beans.xml dosyası eklenir
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	   xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
	   version="1.1" bean-discovery-mode="all">
</beans>
Artık CDI Tomcat'te kullanıma hazırdır. Aşağıdaki gibi deneme amaçlı bir Bean yaratalım
import javax.inject.Named;
@Named
public class Test {
	
	public Test() {}
	
	public String getMessage(){
		
		return "Merhaba CDI Tomcat";
		
	}
}
Bu bean'i bir Servlet'te inject ederek kullanalım
import java.io.IOException;
import javax.inject.Inject;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/TestServlet")
public class TestServlet extends HttpServlet {
	@Inject
	Test test;
	
	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		
		response.getWriter().write(test.getMessage());
		
	}
	
	protected void doPost(HttpServletRequest request, HttpServletResponse response) 
			throws ServletException, IOException {
		doGet(request, response);
	}
}
Web projesini çalıştırıp aşağıdaki gibi (web projenin path'i CdiTomcat) çağırdığımızda "Merhaba CDI Tomcat" cevap olarak dönülecektir.
http://localhost:8080/CdiTomcat/TestServlet
CDI'i JSF ile de kullanabilirsiniz. Ancak bunu yapmak için JSF'de kullanılan bean'leri @ManagedBean ile değil @Named ile işaretlemeniz gerekir. Aynı şekilde javax.enterprise.context içindeki scope'ları kullanmanız , JSF'nin scope'larını kullanmamanız gerekir.
JSF için gerekli bağımlılıkları ekleyelim
<dependency>
	<groupId>com.sun.faces</groupId>
	<artifactId>jsf-api</artifactId>
	<version>2.2.14</version>
</dependency>
<dependency>
	<groupId>com.sun.faces</groupId>
	<artifactId>jsf-impl</artifactId>
	<version>2.2.14</version>
</dependency>
Aşağıdaki gibi bir TestBean yapalım
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.inject.Named;
@Named	
@RequestScoped
public class TestBean {
	@Inject
	Test test;
	
	public TestBean() {}
	
	public String getMessage(){
		
		return test.getMessage();
		
	}
	
}
Bu bean'i bir xhtml sayfasında kullanalım
<!DOCTYPE html>
<html xmlns:h="http://java.sun.com/jsf/html">
<head>
<meta charset="ISO-8859-9"/>
</head>
<body>
	<h:outputLabel value="#{testBean.message}"></h:outputLabel>
</body>
</html>

Bu sayfa tarayıcıda çalıştığında ekranda "Merhaba CDI Tomcat" yazısı görülecektir.
NOT: CDI'da ViewScope bulunmaz. View Scope kullanmak için Omnifaces kütüphanesini kullanmanızı tavsiye ederim. Omnifaces CDI ile çalışan bir kütüphanedir.

İpucu

CDI ile Birim Test

CDI ve JUnit ile sunucuya (tomcat , jboss vb..) gerekli olmadan birim testleri yapılabilmektedir.
Bunun için junit ve weld se kütüphanesi bağımlılıklarını ekleyelim
<dependency>
	<groupId>junit</groupId>
	<artifactId>junit</artifactId>
	<version>4.12</version>
	<scope>test</scope>
</dependency>
<dependency>
	<groupId>org.jboss.weld.se</groupId>
	<artifactId>weld-se-core</artifactId>
	<version>2.2.16.Final</version>
	<scope>test</scope>
</dependency>
Test kodu yazabilmek için öncelikle bir WeldContext sınıfı ekleleyim
import org.jboss.weld.environment.se.Weld;
import org.jboss.weld.environment.se.WeldContainer;
public class WeldContext {
    public static final WeldContext INSTANCE = new WeldContext();
    private final Weld weld;
    private final WeldContainer container;
    private WeldContext() {
        this.weld = new Weld();
        this.container = weld.initialize();
        Runtime.getRuntime().addShutdownHook(new Thread() {
            @Override
            public void run() {
                weld.shutdown();
            }
        });
    }
    public <T> T getBean(Class<T> type) {
        return container.instance().select(type).get();
    }
}
Bu şekilde bean'leri yöneten bir sınıf yaratılmış olur.
Şimdi bir Junit testleri için Runner sınıfı yaratıyoruz:
import org.junit.runners.BlockJUnit4ClassRunner;
import org.junit.runners.model.InitializationError;
public class WeldJUnit4Runner extends BlockJUnit4ClassRunner {
    public WeldJUnit4Runner(Class<Object> clazz) throws InitializationError {
        super(clazz);
    }
    @Override
    protected Object createTest() {
        final Class<?> test = getTestClass().getJavaClass();
        return WeldContext.INSTANCE.getBean(test);
    }
}
Artık test sınıfını aşağıdaki gibi yazabiliriz:
import javax.inject.Inject;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(WeldJUnit4Runner.class)
public class MyUnitTest {
	@Inject
	com.test.Test testObj;
	
	@Test
	public void myTest(){
		
		String message=testObj.getMessage();
		
		Assert.assertEquals("Merhaba CDI Tomcat", message);
		
	}
	
}
Görüldüğü gibi bizim yarattığımız Test sınıfı inject edilmiştir. Eğer classpath'in META-INF'de beans.xml yok ise aşağıdaki gibi bir hata alabilirsiniz :
Caused by: java.lang.IllegalStateException: WELD-ENV-000016: Missing beans.xml file in META-INF
at org.jboss.weld.environment.se.Weld.initialize(Weld.java:131)
at com.test.WeldContext.(WeldContext.java:15)
at com.test.WeldContext.(WeldContext.java:8)
... 18 more
Bunu çözmek için beans.xml'i META-IF klasörüne (yok ise yaratılması gerekir) ekleyin :
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	   xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
	   version="1.1" bean-discovery-mode="all">
</beans>

Artık birim testiniz başarıyla çalışması gerekir.
Bu örnek http://memorynotfound.com/java-se-unit-testing-cdi-junit-jboss-weld-se sayfasından yararlanılarak yapılmıştır.

Materyal

Önder Teker - IoC (Inversion of Control) , Dependency Injection , CDI Nedir ?

IoC (Inversion of Control), Dependency Injection, CDI ve Weld nedir ?
Spring Boot ,Spring MVC, Sping Data, Spring REST nedir?



Bu Sayfayı Paylaş:

İletişim Bilgileri

Takip Et

Her Hakkı Saklıdır. Bu sitede yayınlanan tüm bilgi ve fikirlerin kullanımından fibiler.com sorumlu değildir. Bu sitede üretilmiş , derlenmiş içerikleri, fibiler.com'u kaynak göstermek koşuluyla kendi sitenizde kullanılabilirsiniz. Ancak telif hakkı olan içeriklerin hakları sahiplerine aittir