Spring - @Autowired funktioniert nicht

y0dA

Top Contributor
Hallo!
Im Detail bin ich gerade dabei ein Projekt mit
-) Maven
-) JSF 2.0
-) Spring 3.0
-) Tomcat 6.0

aufzusetzen.

Maven und JSF 2.0 klappt mittlerweile jedoch schaffe ich es gerade nicht dass die Dependency Injection funktioniert mit Annotationen.

spring.config.xml (applicationContext.xml):
Java:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
         [url]http://www.springframework.org/schema/beans/spring-beans-3.0.xsd[/url]
         [url=http://www.springframework.org/schema/context]Index of /schema/context[/url]
         http://www.springframework.org/schema/context/spring-context-3.0.xsd">

	<!-- Scan classpath for Spring components starting at base-package. Automatically 
		inludes: - AutowiredAnnotationBeanPostProcessor - CommonAnnotationBeanPostProcessor -->
	<context:component-scan base-package="at.mpf.mybudget" />

	<context:annotation-config />
</beans>

CustomerService.java
Java:
@Service
public class CustomerService {

	public String test() {
		return "ruf mich an!";
	}
}

Customer (fundiert zu Testzwecken als Controller in der Hoffnung dass DI funktioniert = Fehlanzeige):
Java:
@ManagedBean
@SessionScoped
@Controller
public class Customer {
	private String firstName;
	private String lastName;

	private String test;
	
	@Autowired // ist null..
	private CustomerService customerService;
	
	public String getTest() {
		return this.customerService.test();
	}

	public void setCustomerService(CustomerService customerService) {
		this.customerService = customerService;
	}

	public CustomerService getCustomerService() {
		return customerService;
	}
}

pom.xml - Dependencies
Java:
	<properties>
		<myfaces.version>2.0.2</myfaces.version>
		<spring.version>3.0.4.RELEASE</spring.version>
	</properties>

	<!-- Project dependencies -->
	<dependencies>
		<dependency>
			<groupId>org.apache.myfaces.core</groupId>
			<artifactId>myfaces-api</artifactId>
			<version>${myfaces.version}</version>
			<scope>compile</scope>
		</dependency>

		<dependency>
			<groupId>org.apache.myfaces.core</groupId>
			<artifactId>myfaces-impl</artifactId>
			<version>${myfaces.version}</version>
			<scope>compile</scope>
		</dependency>

		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.0</version>
			<scope>test</scope>
		</dependency>

		<dependency>
			<groupId>log4j</groupId>
			<artifactId>log4j</artifactId>
			<version>1.2.14</version>
			<scope>compile</scope>
		</dependency>

		<dependency>
			<groupId>commons-logging</groupId>
			<artifactId>commons-logging</artifactId>
			<version>1.1.1</version>
		</dependency>

		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>servlet-api</artifactId>
			<version>2.5</version>
			<scope>provided</scope>
		</dependency>

		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-validator</artifactId>
			<version>4.0.2.GA</version>
		</dependency>

		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-api</artifactId>
			<version>1.4.2</version>
		</dependency>

		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-log4j12</artifactId>
			<version>1.4.2</version>
		</dependency>

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-web</artifactId>
			<version>${spring.version}</version>
		</dependency>

	</dependencies>
 
Hi,

zu Testzwecken würde ich einen JUnit-Test machen. Damit bist du unabhängig von der Präsentationstechnologie (in deinem Fall JSF), so z.B.:

Java:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:service.spring.xml" })
@Transactional
public class CategoryServiceTest {

	@Autowired
	private CategoryDao categoryDao;
	private Category category;

	@Before
	public void setUp() {
		category = new Category();
		category.setName("Buher");
	}

	@Test
	public void testInsert() {
		category = categoryDao.save(category);
		assertEquals(category, categoryDao.readByPrimaryKey(category.getId()));
	}
}

Für eine Schichtentrennung ist es auch sinnvoll gegen Interfaces zu programmieren (ist ja auch Sinn von DI)

Ich bin im übrigen an der gleichen Sache dran wie du, d.h. Webprojekt mit Maven, JSF, JPA und Spring. Vielleicht kann man hier voneinander profitieren. Für DAO-Sachen verwende ich übrigens Hades. Erspart einem jede Menge Schreibarbeit. 🙂
 
Danke für deine Antwort.

Das man gegen Interfaces entwickelt ist mir durchaus bewusst..ich habe doch geschrieben dass oben gepostetes zu Testzwecken entstanden ist und nix mit dem eigentlichen Projekt zu tun hat 😉

Bezüglich dem JUnit Test, bei selbigen funktioniert die DI ebenfalls nicht (nehme an weil die spring-config.xml im WEB-INF Ordner liegt).
Wenn ich die spring-config.xml bspw. unter src/main/resource lege klappt die DI.
Brauchen die Tests nicht eigentlich immer eine eigene applicationConfig.xml oder kann ich auch auf die .xml im WEB-INF Ordner für die Tests benutzen?
 
Wenn ich die spring-config.xml bspw. unter src/main/resource lege klappt die DI.
Dort sollte sie auch normal hin. Bei mir liegt sie ebenfalls dort.

Bezüglich dem JUnit Test, bei selbigen funktioniert die DI ebenfalls nicht (nehme an weil die spring-config.xml im WEB-INF Ordner liegt).
Für Tests kannst du ja den SpringJUnit4ClassRunner benutzen (konfiguriert den Container wahrscheinlich so, dass du DI auch in Tests verwenden kannst). Und mit @ContextConfiguration kannst du deine XML-Datei angeben
 
Dort sollte sie auch normal hin. Bei mir liegt sie ebenfalls dort.
Da bin ich mir nicht so sicher, es ist auch egal da die DI selbst dann nicht funktioniert (also wenn die spring-config in src/main/resource liegt).
Hierbei würde mich trotzdem interessieren wie du dann in der web.xml auf die Spring Config verwiesen hast?
Bei mir (da im WEB-INF):
Java:
	<!-- Spring configuration -->
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>
			/WEB-INF/spring-config.xml
		</param-value>
	</context-param>


Für Tests kannst du ja den SpringJUnit4ClassRunner benutzen (konfiguriert den Container wahrscheinlich so, dass du DI auch in Tests verwenden kannst). Und mit @ContextConfiguration kannst du deine XML-Datei angeben
Hmm?
Wie gesagt, den Test habe ich zum laufen bekommen.

Zum eigentlichen Problem gibts keine Idee, also warum es in der Webapplikation nicht funktioniert?
 
Zuletzt bearbeitet:
Hm, im Moment programmiere ich noch den Service-Teil meines Projekts, d.h. wie dann das in meine Web Application kommt, damit hab ich mich noch gar nicht beschäftigt. Ich orientiere mich ein bissl an diesem Beispiel (das man auch runterladen kann). Dort wird Spring bspw. so konfiguriert:
[XML]<!-- Spring configuration-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/web.spring.xml
classpath:service.spring.xml
</param-value>
</context-param>[/XML]
D.h. einmal gibt es eine Spring Config für den Service- und dann noch eine für den Web-Teil (dort wird das Projekt in mehrere Module aufgeteilt, zur besseren Trennung).
 
Selbiges Tutorial habe ich auch schon durch 🙂

Naja vllt. kommt ja noch von anderer Stelle ein Hinweis.

Abgesehen davon, wie löst du die Sache mit Maven - hälst du dich an die Projektstruktur des Tutorials? Also das der Webcontent unter src/main/webapp zu finden ist? Machst du in der Console immer ein mvn eclipse:eclipse - dadurch bekomme ich nämlich "Referenced Libraries" welches für mich neu ist - kannte eigentlich immer nur die "Maven Dependencies" Lib. Vorteil an mvn eclipse:eclipse ist jedoch zweifellos dass unter Deployment Assembly die libs gesetzt werden, das kann m2clipse meines Wissens nicht.
 
Zuletzt bearbeitet:
Java:
@ManagedBean
@SessionScoped
public class Customer {
    private String firstName;
    private String lastName;
 
    private String test;
    
    @Autowired // ist null..
    private CustomerService customerService;
}
--> @ManagedBean
--> @Autowired
Kann es sein dass man die JSF Annotationen und die Spring Annotationen nicht mischen darf?
 
Ich weiß nicht was die Annotation macht...
Aber um den Fehler einzuschränken kannst sie ja mal deklarieren ob es dann geht,
vielleicht wird auch der appilcation context gar nicht gelanden
 
Abgesehen davon, wie löst du die Sache mit Maven - hälst du dich an die Projektstruktur des Tutorials?
Im Prinzip schon. Hab mich auch zu Multimodule-Projekten mit Maven etwas belesen und finde die Struktur eigentlich auch gar nicht so schlecht. Der Vorteil ist, du kannst den Service-Teil vollkommen unabhängig von dem Presentation Layer testen. Wenn ich dann bspw. JSF verwenden möchte (was ich noch machen möchte; momentan bin ich noch am probieren, wie ich ein Maven-Projekt mit JSF aufsetze, habs fast geschafft), dann mache ich einfach ein Webapp-Projekt auf oder was auch immer. Das steht mir frei. Nebenbei kann ich natürlich immer noch nachschauen, wie der Autor das in dem Beispiel gemacht hat.

Für die Maven-Projekterstellung verwende ich m2eclipse, arbeite gar nicht mit der Konsole.

In deinem ApplicationContext.xml (bei dir spring.config.xml) muss noch so etwas wie das hier stehen, damit Spring die Beans auch solche erkennt:
[XML]<context:component-scan base-package="deinPackageName">
</context:component-scan>[/XML]
 

Zurück
Oben