If I want to declare a bean using Spring 3's Java-based configuration, I can do this:
#Configuration
public class MyConfiguration {
#Bean
public MyRepository myRepository() {
return new MyJpaRepository();
}
}
But, since I can't use the #Repository annotation in this context, how do get Spring to perform exception translation?
Declare your MyJpaRepository class as a repository:
#Repository
public class MyJpaRepository {
...
}
And make sure you have your annotations discoverable by setting up the component-scan element in your Spring configuration:
<context:component-scan base-package="org.example.repository"/>
Since you do not want your repository included in the annotation scan per your comments, filter it out either by excluding all #Repository annotations or your particular class(es) or package. There is an example of this in the documentation:
<context:component-scan base-package="org.example.repository">
<!-- use one or the other of these excludes, or both if you *really* want to -->
<context:exclude-filter type="regex" expression="*Repository"/>
<context:exclude-filter type="annotation"
expression="org.springframework.stereotype.Repository"/>
</context:component-scan>
The Spring 3.0 documentation describes this configuration in more detail in section 3.10.
By configuring your class as a Repository, it will be designated as one when you pull it out as a Bean in your Configuration class.
Related
I have a question around the usage of new keyword being used when using java configuration in spring. What is the need of using new keyword
Refer below mentioned example:
Code implemented using Java Config
#Configuration
public class HelloWorldConfig {
#Bean
public HelloWorld helloWorld(){
return new HelloWorld();
}
}
The above code will be equivalent to the following XML configuration
<beans>
<bean id = "helloWorld" class = "com.test.HelloWorld" />
</beans>
In XML config, we do not use new keyword whereas in java config we are using new keyword. can someone please explain the difference
In the XML configuration, you explain to the system what class should be instanciated (there is a "new" but it is behind the scene) but in the Java Config you actually have to return an instance so that is why we use the 'new' keyword. 'new' simply creates an instance of your class.
The two examples shown in question are not really equivalent.
What the
<beans>
<bean id="helloWorld"
class="com.test.HelloWorld" />
</beans>
really does, is it tells Spring to instantiate class com.test.HelloWorld, and name the resulting bean "helloWorld".
Then the java-config approach is not really doing this. Instead this follows the factory-method pattern, when we tell Spring, that the return value of the method is the bean, and the method name is the name of that bean.
An equivalent of that in XML would be the mentioned factory-method approach, which in this case would look something like this:
<beans>
<bean id="helloWorldConfig"
class="com.test.HelloWorldConfig" />
<bean id="helloWorld"
factory-bean="helloWorldConfig"
factory-method="helloWorld" />
</beans>
Note that there are several approaches to factory-method. In the above, we are assuming, the `helloWorldConfig" is the factory, and we're specifying the method on that bean. Theare are cases with static factory methods too. See here for more examples.
<beans>
<bean id = "helloWorld" class = "com.test.HelloWorld" />
</beans>
This XML configurations tells Spring to "create an instance of com.test.HelloWorld and put it in the bean context with bean id helloWorld".
#Configuration
public class HelloWorldConfig {
#Bean
public HelloWorld helloWorld(){
return new HelloWorld();
}
}
In this Java configuration, we are returning an instance of com.test.HelloWorld. Because of the #Bean annotation, this instance is put into the bean context. As no specific bean id is given, the bean id is derived from the method hellowWorld() and thus becomes helloWorld.
As you can see, both configurations require an instance of com.test.HelloWorld. The XML configuration implicitly creates the instance whereas in the Java configuration you have to explicitly do it yourself.
Why post construct does not get called without putting bean in applicationContext.xml
Here is my class which contains #PostConstruct annotation.
package org.stalwartz.config;
import javax.annotation.PostConstruct;
import javax.inject.Singleton;
#Singleton
public class PropertyLoader {
#PostConstruct
public void init() {
System.out.println("PropertyLoader.init()");
}
}
Below is my applicationContext.xml
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:dwr="http://www.directwebremoting.org/schema/spring-dwr" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.directwebremoting.org/schema/spring-dwr
http://www.directwebremoting.org/schema/spring-dwr/spring-dwr-3.0.xsd">
<dwr:annotation-config />
<dwr:annotation-scan base-package="org.stalwartz" scanDataTransferObject="true" scanRemoteProxy="true" />
<dwr:url-mapping />
<!-- <bean id="proeprtyLoader" class="org.stalwartz.config.PropertyLoader"></bean> -->
<dwr:controller id="dwrController" debug="false">
<dwr:config-param name="activeReverseAjaxEnabled" value="true" />
</dwr:controller>
<context:annotation-config>
<context:component-scan base-package="org.stalwartz" annotation-config="true"></context:component-scan>
</context:annotation-config>
<mvc:annotation-driven />
...
...
...
</beans>
Looks simple, but it does not work without uncommenting bean declaration.
In Spring environment initialization callback method (the one annotated by #PostConstruct) make sense only on spring-managed-beans. To make instance(s) of your PropertyLoader class managed, you must do one of the following:
Explicitly register your class in context configuration (as you did)
<bean id="proeprtyLoader" class="org.stalwartz.config.PropertyLoader"></bean>
Let component scanning do the work (as you nearly did), but classes must be annotated by one of #Component, #Repository, #Service, #Controller.
Note from Spring documentation: The use of <context:component-scan> implicitly enables the functionality of <context:annotation-config>. There is usually no need to include the <context:annotation-config> element when using <context:component-scan>.
Because putting bean in applicationContext.xml you are adding bean to Spring container, which has interceptor for this annotation. When Spring inject beans it checks #PostConstruct annotation, between others.
When you call simple new PropertyLoader() JVM will not search for the #PostConstruct annotation.
From doc of #PostConstruct annotation:
The PostConstruct annotation is used on a method that needs to be executed
after dependency injection is done to perform any initialization. This
method MUST be invoked before the class is put into service. This
annotation MUST be supported on all classes that support dependency
injection. The method annotated with PostConstruct MUST be invoked even
if the class does not request any resources to be injected.
Singleton is a scope annotation. It can be used to declare 'singletone' scope for a particular bean, but not instantiate it. See this article.
If you want to instantiate your class as singleton you can try Spring Service annotation.
#Service
public class PropertyLoader {
#PostConstruct
public void init() {
System.out.println("PropertyLoader.init()");
}
}
Also, you can replace annotation-config tag with component-scan. Here is a good article about differences of annotation-config and component-scan tags.
you are using #Singleton from javax.inject package which is not picked up as bean by spring container. Change it to :
package org.stalwartz.config;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
#Component
public class PropertyLoader {
#PostConstruct
public void init() {
System.out.println("PropertyLoader.init()");
}
}
and the spring will auto detect PropertyLoader and will include it in Spring container as bean via the #Component annotation and this bean will be with singleton scope
by default a bean is singleton scoped in Spring, and #PostConstruct is usually used for service beans and service beans must scoped prototype and here because you need multiple objects for that particular class, Spring will provide you singleton instance.
also by doing this spring will attempt multiple times to find this service bean and finally throws below exception:
java.lang.NoClassDefFoundError: Could not initialize class org.springframework.beans.factory.BeanCreationException
so try like this in annotation way:
package org.stalwartz.config;
import javax.annotation.PostConstruct;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
#Component
#Scope("prototype") //you have to make it prototype explicitly
public class PropertyLoader {
#PostConstruct
public void init() {
System.out.println("PropertyLoader.init()");
}
}
Now every thing is good, and work fine for you.
add this dependency to pom.xml
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.2</version>
</dependency>
Below is a snippet from the camle-osgi example. I can obtain the camel context but how do I get the original spring application context? Or how am I supposed to get a reference to "mybean"?
MyRouteBuilder.java:
public class MyRouteBuilder extends RouteBuilder {
public static void main(String[] args) throws Exception{
new Main().run(args);
}
public void configure() {
// set up the transform bean
ModelCamelContext mc = getContext();//ok, I can get the camel context fine
//but how to get the spring context to get to "mybean"???
//set up routes
}
}
beans.xml:
<beans>
<camel:camelContext xmlns="http://camel.apache.org/schema/spring">
<package>org.apache.servicemix.examples.camel</package>
-----
</route>
</camel:camelContext>
<bean id="mybean" class="myclass"/>
</beans>
You should not use the spring context directly. Instead use the spring features to inject the beans you need.
Define the routebuilder as a bean in the spring context and use a setter and to inject myBean.
Keep the auto discovery and use annotations like #Autowired in the routebuilder to inject mybean.
A third option is to use getContext().getRegistry(). The registry allows to access all beans of the spring context by name or by type.
It would not be camel if we are already out of options :-)
So another options is to use the bean component of camel to access beans from the spring context: http://camel.apache.org/bean.html
I have an aspect advice that tracks the execution of classes annotated with #Service. The code is currently working but I would like to change it to track REST endpoints on controllers instead of autowired services. Here is the code:
#Aspect
public class AuditingAspect
{
#Pointcut(
//TODO Change pointcut from public methods in Services to REST endpoints in Controllers
"execution(public * my.base.package..*.*(..))" //Must be in package
//+ " && #within(org.springframework.stereotype.Service)" //Has to be a service
+ " && #within(org.springframework.stereotype.Controller)" //Has to be a controller
)
public void auditLoggingPointCut() {
//no op
}
#Around(value ="auditLoggingPointCut()")
public Object logAround(final ProceedingJoinPoint joinPoint) throws Throwable
{
System.out.println("Exection");
returnVal = joinPoint.proceed();
// Now Do The After Logging Part
afterReturningLog(joinPoint, returnVal) ;
return returnVal;
}
private void afterReturningLog(final JoinPoint joinPoint, final Object returnValue)
{
System.out.println("Exiting");
}
}
When I change the "within" from #Service to #Controller, I don't see any output from the advice but the method executes when accessed from the URL. What is different about a Controller that would ignore execution?
The Controller class looks like this:
#Controller
public class CaseReferralEndpoints {
#Autowired
CaseReferralFacade caseReferralFacade;
#RequestMapping(value="/backgroundcheck/getcasereferrals", method = RequestMethod.GET)
#ResponseBody
public List<CaseReferralSection> getCaseReferrals(#RequestParam("caseID") Long caseID) {
return caseReferralFacade.getCaseReferrals(caseID);
}
}
Here is my applicationContext-aop.xml The full config is much larger but I believe this is the most relevant.
<?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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean class="gov.dhs.uscis.elis2.backend.services.logging.AuditingAspect"/>
<aop:aspectj-autoproxy proxy-target-class="false" />
</beans>
Supposing that your #within configuration is correct, a potential remedy to your troubles would be the following:
<aop:aspectj-autoproxy proxy-target-class="true" />
Also you will have to add CGLIB to your classpath
The above steps are needed since your controller does not implement an interface
Finally if you have a root context and a web context, the aop related stuff needs to be applied to the web context (having it in the root context will not work for the controllers that are configured in the web context)
UPDATE
In Gradle to add CGLIB to the classpath add:
'cglib:cglib:2.2.2'
In Maven it would be:
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2.2</version>
</dependency>
Error was found inside of the applicationContext.xml
My controllers were being filtered out of context scanning! I'm one of many developers on the project so I did not think to look here initially.
<context:component-scan>
<!-- a bunch of packages -->
<context:exclude-filter expression="org.springframework.stereotype.Controller" type="annotation"/>
</context:component-scan>
However, I ended up adding an Interceptor which has proven to be closer to what I wanted. Because all of our user actions are REST driven it was easier and cleaner to audit the invocation of REST calls than try and track autowired service methods.
As your pointcut expression is having
#within(org.springframework.stereotype.Service)
with && symbol , advice is going to apply only within your package upto service.
and i hope your controller class is not inside ..Service package, it might be inside
.*.*Controller package so its not executing for controller
solution
Remove within inside point cut expression
or add controller also inside point cut expression
Assuming your pointcut is correct, and you are using two spring contexts, one for the services/daos (appcontext) and one for the controllers (servletcontext), my tip goes in the direction of misconfiguration.
AOP configuration is one of the spring beans which are applied ONLY inside the context it is declared/scanned.
So assuming you have a servletcontext.xml for your controllers your pointcuts wont be applied unless you declare the aop context configuration within this context.
(The application context declaration will be needed if you want to apply the pointcuts to your services.)
I use org.springframework.web.jsf.el.SpringBeanFacesELResolver in my JSF + Spring application. Every backing bean needs an interface to be resolved. I guess that it's interface type of dependency injection.
#{bean.text}
public interface IBean {
String getText();
}
#Named
#Scope("session")
public class Bean implements IBean {
public String getText() {
return "Hello World!";
}
}
I would like to get rid of the interface. It's kind of bureaucracy for me. Is it possible?
I finally solved it. The problem was in beans with scope depending on HTTP (request, session). By default interfaces should be manually created. This can be avoided by using proxies.
If using component scan:
<context:component-scan base-package="..." scoped-proxy="targetClass" />
Or in bean definition:
<bean ...>
<aop:scoped-proxy>
</bean>
See chapter 4.5.4.5 Scoped beans as dependencies in Spring documentation. http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/beans.html