Spring Lazy-init not working with #Resource injection - spring

I have an interface with real and mock implementation. for obvious reasons the mock implementation is not in the production classpath.
I inject the bean using:
#Resource (name="${myClient}")
I am using Spring MVC and injecting this into a #Controller.
In external configuration I set the actual bean name to use and bind it to 'myClient' parameter. The binding works and it tries to load the real implementation but also fails on ClassNotFound on my mock although marked as lazy-init=true.
I am using Spring 4.0.0.
I know this is expected when suing #Autowire, but with #Resource I don't expect it to try and instantiate all beans in spring xml.
Any ideas wha't going on?
Here is the stack trace:
Caused by: org.springframework.beans.factory.CannotLoadBeanClassException: Cannot find class [MyMock] for bean with name 'myClientMock' defined in URL [file:/C:/myProject/target/classes/META-INF/springContext.xml]; nested exception is java.lang.ClassNotFoundException: MyMock1
at org.springframework.beans.factory.support.AbstractBeanFactory.resolveBeanClass(AbstractBeanFactory.java:1327)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.predictBeanType(AbstractAutowireCapableBeanFactory.java:594)
at org.springframework.beans.factory.support.AbstractBeanFactory.isFactoryBean(AbstractBeanFactory.java:1396)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doGetBeanNamesForType(DefaultListableBeanFactory.java:382)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanNamesForType(DefaultListableBeanFactory.java:361)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanNamesForType(DefaultListableBeanFactory.java:347)
at org.springframework.context.support.AbstractApplicationContext.getBeanNamesForType(AbstractApplicationContext.java:1051)
at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.initHandlerMethods(AbstractHandlerMethodMapping.java:105)
at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.afterPropertiesSet(AbstractHandlerMethodMapping.java:89)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping.afterPropertiesSet(RequestMappingHandlerMapping.java:163)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1612)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1549)

I dont know if you´re using Spring profiles, but it´s what we use here to initialize different beans per environment.
From Tomcat we spcecify which profile use, and in Spring we have configure something like this.
<beans profile="deployed-local">
<util:properties id="propertyConfigurer" location="classpath:app.deployed-performance.properties"/>
<context:property-placeholder location="classpath:app.deployed-performance.properties,classpath:app.constants.properties"/>
<import resource="spring/jdbc-config-test.xml"/>
<import resource="spring/contacts-config-deployed.xml"/>
<import resource="spring/security-config-local.xml"/>
<import resource="spring/clamAV-service.xml"/>
<import resource="spring/document-service.xml"/>
</beans>
<beans profile="deployed-prod">
<import resource="spring/jdbc-config.xml"/>
<import resource="spring/contacts-config-deployed.xml"/>
<import resource="spring/security-config.xml"/>
<import resource="spring/clamAV-service.xml"/>
<import resource="spring/document-service.xml"/>
</beans>

Related

Why we use factory-method="aspectOf" in aspect configuration

I found some code in my project.By seeing that i am confused how it scanning the package.we are not mentioning aspect package com.abc.b any where.I have few question
Why aop:aspectj-autoproxy is commentout in xml file?
why is used ?
How com.abc.b package is scanned by spring or there is no need of it or It has link from 'factory-method="aspectOf"'
serviceContext.xml
<?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"
xmlns:cxf="http://cxf.apache.org/core"
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://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd" default-lazy-init="true">
<import resource="classpath:META-INF/cxf/cxf.xml" />
<import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" />
<import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
<!-- <aop:aspectj-autoproxy /> -->
<!-- Enable message logging using the CXF logging feature -->
<cxf:bus>
<!-- <cxf:features>
<cxf:logging/>
</cxf:features> -->
<cxf:inFaultInterceptors>
<bean class="com.flipswap.interceptor.cxf.SafeLoggingInFaultInterceptor"/>
</cxf:inFaultInterceptors>
</cxf:bus>
<context:component-scan base-package="com.abc.service.impl,">
<context:exclude-filter type="annotation" expression="org.aspectj.lang.annotation.Aspect"/>
</context:component-scan>
<bean id="eSSyncAspect" class="com.abc.b.ES" factory-method="aspectOf"/>
.
.
.
ES.java
package com.abc.b;
#Aspect
public class ES{
// some code
}
Unless you specify a custom instantiation model, aspects are by default singletons. That means - in case your code is properly woven -, that you can access the singleton instance of the aspect with AspectName.aspectOf().
In order for your classes to be woven by the AspectJ weaver, you need to either use compile-time/build-time weaving or load-time weaving.
In your spring configuration you are telling Spring to configure your aspect as a spring bean by telling how to access the singleton instance (through the static 'factory' method aspectOf). Spring will do the usual configuration (autowiring and any configured post-processors) on the singleton aspect instance.
aop:aspectj-autoproxy is commented out in your configuration because that would conflict with native aspectj support, as it would enable Spring AOP's dynamic proxy based AOP solution, which is very limited compared to native aspectj, and has a different mechanism to configure aspect beans than the one used in your configuration, namely through the static factory method AspectName.aspectOf().
In most cases, AspectJ aspects are singletons, with one instance per class loader. This single instance is responsible for advising multiple object instances.
A Spring IoC container cannot instantiate an aspect, as aspects don't have callable constructors. But it can obtain a reference to an aspect using the static aspectOf() method that AspectJ defines for all aspects, and it can inject dependencies into that aspect.
7.2.1.1. Example
Consider a security aspect, which depends on a security manager. This aspects applies to all changes in the value of the balance instance variable in the Account class. (We couldn't do this in the same way using Spring AOP.)
The AspectJ code for the aspect (one of the Spring/AspectJ samples), is shown below. Note that the dependency on the SecurityManager interface is expressed in a JavaBean property:
public aspect BalanceChangeSecurityAspect {
private SecurityManager securityManager;
public void setSecurityManager(SecurityManager securityManager) {
this.securityManager = securityManager;
}
private pointcut balanceChanged() :
set(int Account.balance);
before() : balanceChanged() {
this.securityManager.checkAuthorizedToModify();
}
We configure this aspect in the same way as an ordinary class. Note that the way in which we set the property reference is identical. Note that we must use the factory-method attribute to specify that we want the aspect "created" using the aspectOf() static method. In fact, this is locating, rather than, creating, the aspect, but the Spring container doesn't care:
<bean id="securityAspect"
class="org.springframework.samples.aspectj.bank.BalanceChangeSecurityAspect"
factory-method="aspectOf">
<property name="securityManager" ref="securityManager"/>
</bean>We don't need to do anything in Spring configuration to target this aspect. It contains the pointcut information in AspectJ code that controls where it applies. Thus it can apply even to objects not managed by the Spring IoC container.

Prevent Spring from meddling with CDI annotations even for factory created instances

I have a legacy product's JAR that contain Spring (4.3.8) managed classes. I need to integrate it with CDI (JavaEE 7).
I have an interface from the legacy JAR, that is implemented by a CDI bean. The CDI bean is requested from the CDI BeanManager and returned from a factory method. The factory method is registered inside Spring XML and works as expected.
The problem occurs, when a Spring bean of the legacy JAR depends on the implemented interface. Spring than injects the CDI implementation instance and scans the class it for known annotations, namingly #Inject. It then tries to resolve the dependency, which doesn't work since the dependency is not available to Spring.
I already tweaked context:property-placeholder excludes, but that changes nothing.
So how can I tell Spring to stop trying to inject something in my factory produced bean instance?
I finally was able to solve (work around) the problem. I had to remove all CDI-Annotations in the legacy JAR (by replacining them with their Spring counterparts), so spring would any longer work.
Then I added the following XML block to the applicationContext.xml of my CDI WAR:
<context:component-scan annotation-config="false" base-package="com.example">
</context:component-scan>
<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor">
<property name="autowiredAnnotationTypes">
<set>
<value>org.springframework.beans.factory.annotation.Autowired</value>
<value>org.springframework.beans.factory.annotation.Value</value>
</set>
</property>
</bean>
<bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor" />
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
<bean class="org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor" />
<bean class="org.springframework.beans.factory.annotation.CustomAutowireConfigurer">
<property name="customQualifierTypes">
<set>
<value>org.springframework.beans.factory.annotation.Qualifier</value>
</set>
</property>
</bean>
Basically that drops the support for #Inject, etc. from Spring and leaves it where it belongs: CDI.
It's a bit easier.
AutowiredAnnotationBeanPostProcessor is already a bean, so you can configure it before Spring starts to scan with a ServletContextListener to exclude #Inject annotations. At least from Spring 4.1+, AutowiredAnnotationBeanPostProcessor has a method setAutowiredAnnotationTypes, e.g.:
#WebListener
public class ApplicationConfigListener implements ServletContextListener {
#Override
public void contextInitialized(ServletContextEvent event) {
ApplicationContext appCtx = WebApplicationContextUtils.getWebApplicationContext(event.getServletContext());
Set<Class<? extends Annotation>> autowiredAnnotationTypes = new LinkedHashSet<Class<? extends Annotation>>();
AutowiredAnnotationBeanPostProcessor bean = appCtx.getBean(AutowiredAnnotationBeanPostProcessor.class);
autowiredAnnotationTypes.add(Autowired.class);
autowiredAnnotationTypes.add(Value.class);
bean.setAutowiredAnnotationTypes(autowiredAnnotationTypes);
}
}
You could use a SpringBeanAutowiringInterceptor too.
This is explained here.

shared context:property-placeholder in spring application

I have a Spring application which a resource (property-placeholder) isn't shared across my spring contexts.
I've defined the ContextLoaderListener in my web.xml, and it loads a root-context.xml, where is defined a <context:property-placeholder location="classpath:file.properies" />
Then my application have a portlet in it, and when I try to use some property which is defined in file.properties in the myportlet-context.xml, spring can't find that value.
Have I missed something to do?
Aren't the resources defined from the ContextLoaderListener shared across all the contexts?
i think you have to load the <context:property-placeholder location="classpath:file.properies" /> in dispatcher servlet..

spring basic mvc sample application, annotation scan confusion

Little confused, the basic spring mvc app has this:
app-config.xml
<context:component-scan base-package="org.springframework.samples.mvc.basic" />
and the mvc-config.xml has:
<!-- Configures the #Controller programming model -->
<mvc:annotation-driven />
Do you really need both?
for component-scan, does this mean if I don't put the correct package path my #Controller and #Service markers will have no effect?
If I need more than one package, do I just duplicate the entry?
I tried using just the mvc:annotation-driven but that didn't work, I had to put com.example.web.controllers in the component-scan xml node to make it work.
context:component-scan is clear
Scans the classpath for annotated components that will be auto-registered as Spring beans. By default, the Spring-provided #Component, #Repository, #Service, and #Controller stereotypes will be detected.
So #Controller is just a Spring bean. Nothing else.
And
mvc:annotation-driven
registers the HandlerMapping and HandlerAdapter required to dispatch requests to your #Controllers
Which is similar to
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"/>
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"/>
If I need more than one package, do I just duplicate the entry?
You can if you want. context:component-scan is just a bean post-processor.
<context:component-scan base-package="br.com.app.view.controller"/>
<context:component-scan base-package="br.com.app.service"/>
Or
Use a comma-separated list of packages to scan for annotated components.
<context:component-scan base-package="br.com.app.view.controller,br.com.app.service"/>
mvc:annotation-driven allows you to configure behavior of Spring MVC. See details in documentation .For basic usage of Spring MVC you do not need it.
If you need more than one package just mention parent one: <context:component-scan base-package="org.springframework.samples.mvc" />

Getting access to a spring bean from a webservice?

I have created a cxf webservice within my cxf.xml file I have the following tag.
bean id="videoStatsTable" class="com.company.auth.dataobjects.VideoStatsTable"
From what I understand Spring should create this object for me. The problem is I'm not sure how to get access to it. It seems as if I need the servletContext but as I'm in not in a servlet im in a WS im not sure how to do this?
W
Spring has a simplifed way of declaring web services (wiht cxf).
in your applicationContext.xml add xmlns:jaxws="http://cxf.apache.org/jaxws" to your root tag (<beans>) and
http://cxf.apache.org/core
http://cxf.apache.org/schemas/core.xsd
http://cxf.apache.org/jaxws
http://cxf.apache.org/schemas/jaxws.xsd
to your schemaLocation
Then add:
<!-- Loading CXF modules -->
<import resource="classpath:META-INF/cxf/cxf.xml" />
<import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" />
<import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
And finally declare your WebService implementation:
<jaxws:endpoint id="MyWebService" implementor="#MyWebServiceImpl"
address="/myWebServiceAddress" />
where #MyWebServiceImpl is the ID of your bean. You can freely inject any other spring dependencies into that bean.
Then the web service will be accessible through http://yourhost/cxfuri/myWebServiceAddress (where cxfuri is the mapping of your CXF Servlet)

Resources