Spring Boot Java Config - split web (controllers, etc), and services - spring

In my old XML config projects, I could do the following in my configurations
mvc-context.xml
<context:component-scan base-package="com.foo" use-default-filters="false">
<context:include-filter expression="org.springframework.stereotype.Controller" type="annotation"/>
</context:component-scan>
<mvc:annotation-driven/>
service-context.xml
<context:spring-configured />
<context:annotation-config />
<context:component-scan base-package="com.foo" >
<context:exclude-filter expression="org.springframework.stereotype.Controller" type="annotation"/>
</context:component-scan>
in my tests, I could then do the following
#RunWith(SpringJUnit4ClassRunner.class)
#WebAppConfiguration
#ContextHierarchy(value = {
#ContextConfiguration(classes = { MockServices.class }),
#ContextConfiguration({ "classpath:/META-INF/spring/mvc-servlet-context.xml" }),
})
public class FooControllerTest {
#Autowired
private WebApplicationContext wac;
private MockMvc mvc;
#Before
public void setUp() throws Exception {
mvc = webAppContextSetup(wac).build();
}
}
and I could then run tests against the my MVC configuration, without loading my services and JPA respositories, and instead have my mocks #Autowired into my controllers.
However, Spring Boot applications have the following in the main context configuration
#Configuration
#ComponentScan
#EnableAutoConfiguration
public class Application {
}
This #ComponentScan obviously finds all #Controller, #Service, etc
if I now tried to test my MVC context, I would load the unwanted services and repositories.
What I attempted to do was create 2 new configurations
Mvc.java
#Configuration
#ComponentScan(basePackages = { "com.foo" }, useDefaultFilters = false, includeFilters = {#Filter(value = org.springframework.stereotype.Controller.class)} )
#Order(2)
public class Mvc {
}
Services.java
#Configuration
#ComponentScan(basePackages = { "com.foo" }, useDefaultFilters = false, excludeFilters = {#Filter(value = org.springframework.stereotype.Controller.class)} )
#Order(1)
public class Services {
}
This however does not work, when I try start my app, I will get #Autowire errors No qualifying bean of type
Am I going about this the wrong way?
How do I make it so that I can run tests on my MVC context, without the time penalty of loading JPA EntityManagers, Spring Data Repositories, etc?

The solution M. Deinum gave in the comments is correct but may be you didn't get the hint.
when you say:
useDefaultFilters = false and excludeFilters = {#Filter(value = org.springframework.stereotype.Controller.class)}
nothing will be found because useDefaultFilters = false will prevent spring from looking for stereotype annotations like #Controller, #Service ...
Link to Spring API doc

Related

Set default proxyMode for spring

To serialize the session of my spring webapplication i have to change my annotations from
#Controller
#Scope("request")
to
#Controller
#Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
is it possible to change the default proxyMode in applicationContext.xml?
I am terribly late on this question, but still would be useful for other people.
You can set up default proxy mode in the XML also.
<beans>
<context:component-scan base-package="org.example" scoped-proxy="interfaces"/>
</beans>
You can change the value of the scoped-proxy attribute as per your need.
This can also be done using annotation, in a spring boot application.
#SpringBootApplication
#ComponentScan(basePackages = "org.example", scopedProxy = ScopedProxyMode.TARGET_CLASS)
public class SpringBootApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootHelloWorldApplication.class, args);
}
}
https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-scanning-scope-resolver

#Autowired not working in spring Integration

In service implementation,with help of #Autowired i am injecting CollectInfo object in serviceImpl but i am getting NullPointerException.
package net.group.cts.service.serviceImpl;
#Service
public class EmployeeImpl implements EmployeeService {
#Autowired
CollectInfo info;
public void processData(){
info.getName();
}
}
package net.group.cts.model;
#Component
public class CollectInfo (){
String name;
public String getName(){
name = name + "Mr.";
return name;}
}
}
Xmlconfig.xml
<context:annotation-config/>
<context:component-scan base-package="net.group.cts"/>
<bean id="info" class="net.group.emp.model.CollectInfo "/>
You cannot inject a bean in a class if this class is not a Spring bean.
EmployeeImpl is not annotated with any Spring bean stereotype such as #Component or #Service.
Add one of them on EmployeeImpl and ensure that the two classes are located inside the package scanned by Spring <context:component-scan base-package="net.group.emp.service"/>
and it should be ok.
Besides, both annotating a bean with #Component :
#Component
public class CollectInfo (){...}
and configuring it in the Spring xml configuration :
<bean id="info" class="net.group.emp.model.CollectInfo "/>
is redundant. It will finally create two beans : one name collectInfo and another named info.
I advise you to favor annotation over xml configuration as it is possible (it is the very most of cases).

#Autowired dependencies are null in compile time weaving of #Aspect class [duplicate]

I have the following spring configuration:
<context:component-scan base-package="uk.co.mysite.googlecontactsync.aop"/>
<bean name="simpleEmailSender" class="uk.co.mysite.util.email.simple.SimpleEmailSenderImplementation"/>
<aop:aspectj-autoproxy/>
Then I have an aspect:
#Aspect
public class SyncLoggingAspect {
#Autowired
private SimpleEmailSender simpleEmailSender
#AfterReturning(value="execution(* uk.co.mysite.datasync.polling.Poller+.doPoll())", returning="pusher")
public void afterPoll(Pusher pusher) {
simpleEmailSender.send(new PusherEmail(pusher));
}
}
This aspect works (I can hit a breakpoint on afterPoll) but simpleEmailSender is null. Unfortunately I cannot find clear documentation on why this is. (For the record, my simpleEmailSender bean exists and is correctly wired into other classes) The following things confuse me:
Is context:component-scan supposed to be picking up #Aspect? If it is then surely it would be a spring managed bean, thus autowired should work?
If context:component-scan isn't for creating aspects, how is my aspect being created? I thought aop:aspectj-autoproxy just creates a beanPostProcessor to proxy my #Aspect class? How would it do this if it isn't a spring managed bean?
Obviously you can tell I don't have an understanding of how things should be working from the ground up.
The aspect is a singleton object and is created outside the Spring container. A solution with XML configuration is to use Spring's factory method to retrieve the aspect.
<bean id="syncLoggingAspect" class="uk.co.demo.SyncLoggingAspect"
factory-method="aspectOf" />
With this configuration the aspect will be treated as any other Spring bean and the autowiring will work as normal.
You have to use the factory-method also on Enum objects and other objects without a constructor or objects that are created outside the Spring container.
For Spring Boot to use #Autowired with AspectJ I have found the following method.
In configuration class add your aspect:
#Configuration
#ComponentScan("com.kirillch.eqrul")
public class AspectConfig {
#Bean
public EmailAspect theAspect() {
EmailAspect aspect = Aspects.aspectOf(EmailAspect.class);
return aspect;
}
}
Then you can successfully autowire your services in your aspect class:
#Aspect
public class EmailAspect {
#Autowired
EmailService emailService;
Another option is to add #Configurable to your aspect class instead of messing around with XML.
Configuring #Autowired with java config only (so no XML based configuration) requires a bit of extra work than just adding #Configuration to the class, as it also needs the aspectOf method.
What worked for me was creating a new class:
#Component
public class SpringApplicationContextHolder implements ApplicationContextAware {
private static ApplicationContext applicationContext = null;
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
And then use that in you aspect in conjunction with using #DependsOn #Configured and #Autowired:
#DependsOn("springApplicationContextHolder")
#Configuration
#Aspect
public class SomeAspect {
#Autowired
private SomeBean someBean;
public static SomeAspect aspectOf() {
return SpringApplicationContextHolder.getApplicationContext().getBean(SomeAspect.class);
}
The #DependsOn is needed because spring can't determine the dependency because the bean is used staticly.
I dont have 50 rep to comment on a question so here is another answer relating to #
Jitendra Vispute answer.
The official Spring doc mentions:
You may register aspect classes as regular beans in your Spring XML configuration, or autodetect them through classpath scanning - just like any other Spring-managed bean. However, note that the #Aspect annotation is not sufficient for autodetection in the classpath: For that purpose, you need to add a separate #Component annotation (or alternatively a custom stereotype annotation that qualifies, as per the rules of Spring’s component scanner).Source: Spring '4.1.7.Release' documentation.
This would mean that adding a #Component annotation and adding the #ComponentScan on your Configuration would make #Jitendra Vispute's example work. For the spring boot aop sample it worked, though I did not mess around with context refreshing.Spring boot aop sample:
Application:
package sample.aop;
#SpringBootApplication
public class SampleAopApplication implements CommandLineRunner {
// Simple example shows how an application can spy on itself with AOP
#Autowired
private HelloWorldService helloWorldService;
#Override
public void run(String... args) {
System.out.println(this.helloWorldService.getHelloMessage());
}
public static void main(String[] args) throws Exception {
SpringApplication.run(SampleAopApplication.class, args);
}
}
The application should also run as plain Spring Framework application with the following annotations instead of #SpringBootApplication:
#Configuration
#EnableAspectJAutoProxy
#ComponentScan
and an AnnotationConfigApplicationContext instead of SpringApplication.
Service:
package sample.aop.service;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
#Component
public class HelloWorldService {
#Value("${name:World}")
private String name;
public String getHelloMessage() {
return "Hello " + this.name;
}
}
Monitor Aspect:
package sample.aop.monitor;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
#Aspect
#Component
public class ServiceMonitor {
#AfterReturning("execution(* sample..*Service.*(..))")
public void logServiceAccess(JoinPoint joinPoint) {
System.out.println("Completed: " + joinPoint);
}
}
This blog post explains it really well. Due to the fact that aspect singleton is created outside spring container you'd need to use factory-method=”aspectOf” that is only available after it is woven in by AspectJ ( not Spring AOP ) :
Notice factory-method=”aspectOf” that tells Spring to use a real
AspectJ ( not Spring AOP ) aspect to create this bean. So that after
the aspect is woven in it has an
“aspectOf” method.
So that :
No matching factory method found: factory method 'aspectOf()' - That
would mean that the aspect was not woven by AspectJ weaver.
From my experience with spring 3.1, if I don't use #Autowired but traditional setter for dependency injection, it gets injected and works as expected without aspectJ weaver. Although I'm encountering problems with the aspect being singleton... It results in 'perthis' instantiation model.
.
Add #Component to aspect class and your dependencies should get injected automatically.
and add context:component-scan for package where your aspect is in spring context file.
#Component
#Aspect
public class SomeAspect {
/* following dependency should get injected */
#Autowired
SomeTask someTask;
/* rest of code */
}
Use compile time weaving, see for plugin example at: https://github.com/avner-levy/minimal_spring_hibernate_maven_setup/blob/master/pom.xml
The following combination of annotation and Spring config works for me thanks to notes above by Tobias/Willie/Eric:
Class:
package com.abc
#Configurable
#Aspect
public class MyAspect {
#Autowired
protected SomeType someAutoWiredField;
}
XML:
<context:spring-configured />
<context:component-scan base-package="com.abc" />
#Configurable(autowire = Autowire.BY_TYPE)
Add this annotation to your Aspectj class. Then it will be handled by Spring IOC.
For Spring Boot using #Autowired in #Aspect,
my way is using spring.factories configuration file
create a file named spring.factories in src/main/resources
the file content is as following
org.springframework.boot.autoconfigure.EnableAutoConfiguration=pack.age.to.YourAspect,pack.age.to.YourDAO

Overriding an Autowired Bean in Unit Tests

Is there a simple way I can easily override an autowired bean in specific unit tests? There is only a single bean of every type in the compile classes so it's not a problem for autowiring in this case. The test classes would contain additional mocks. When running a unit test I'd simply like to specify an additional Configuration that says basically, while running this unit test use this mock instead of the standard bean.
Profiles seem a bit overkill for what I require and I'm not sure this would be achievable with the Primary annotation as different unit test could have different mocks.
If you just simply want to provide a different bean in your tests, i think you don't need to use spring profiles or mockito.
Just do the following:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = { TestConfig.class })
public class MyTest
{
#Configuration
#Import(Application.class) // the actual configuration
public static class TestConfig
{
#Bean
public IMyService myService()
{
return new MockedMyService();
}
}
#Test
public void test()
{
....
}
}
NOTE: tested with spring boot 1.3.2 / spring 4.2.4
In Spring Boot 1.4 there's a simple way for doing that:
#RunWith(SpringRunner.class)
#SpringBootTest(classes = { MyApplication.class })
public class MyTests {
#MockBean
private MyBeanClass myTestBean;
#Before
public void setup() {
...
when(myTestBean.doSomething()).thenReturn(someResult);
}
#Test
public void test() {
// MyBeanClass bean is replaced with myTestBean in the ApplicationContext here
}
}
I had similar problem and I solved with a mix and I find this one more useful and reusable. I created a spring profile for the tests and a config class that overrides the beans I want to mock in a very simple way:
#Profile("test")
#Configuration
#Import(ApplicationConfiguration.class)
public class ConfigurationTests {
#MockBean
private Producer kafkaProducer;
#MockBean
private SlackNotifier slackNotifier;
}
By doing that I can #Autowire those mock beans and use mockito to verify on them. Main advantage is that now all tests seamlessly get the mock beans without any per-test change.
Tested with:
spring boot 1.4.2
You should use spring profiles in order to know what kind of bean you want to use in different contexts.
http://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-profiles.html
Since Spring Boot 1.4.0 instead of explicitly specifying #Configuration for tests, simply add static nested class annotated with #TestConfiguration and provide your replacement #Bean annotated with #Primary.
#TestConfiguration will be added to your primary Spring Boot test context (which means your production bean will still be created), but the one from #TestConfiguration will be used, because of the #Primary.
As mats.nowak commented, #ContextConfiguration is useful for this.
Say a parent test class is like:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {"classpath:spring/some-dao-stuff.xml"
,"classpath:spring/some-rest-stuff.xml"
,"classpath:spring/some-common-stuff.xml"
,"classpath:spring/some-aop-stuff.xml"
,"classpath:spring/some-logging-stuff.xml"
,"classpath:spring/some-services-etc.xml"
})
public class MyCompaniesBigTestSpringConfig {
...
Create a child test class:
package x.y.z;
#ContextConfiguration
public class MyOneOffTest extends MyCompaniesBigTestSpringConfig {
...
and put in src/test/resources/x/y/z/MyOneOffTest-context.xml
<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
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<bean id="widgetsService" class="com.mycompany.mydept.myservice.WidgetsService" primary="true" />
</beans>
That widgetsService bean will override (take the place of) the bean defined in the main config xml (or Java config). See about inheritLocations
Also Note the default -context.xml file. Example of that here.
Update: I had to add primary="true", apparently it's needed.

Spring dependency injection in Security.Authenticator

I have written a custom authenticator for my Play 2.3.4 application which has spring dependency injection configured. I want to be able to inject an 'authService' into my authenticator, but this is not working. My authService is always null. Is it possible to configure autowired injection into authenticators? My authenticator is as follows:
package controllers;
#org.springframework.stereotype.Component
public class AppAuthenticator extends Security.Authenticator {
#Autowired
#Qualifier("authService")
private AuthService authService;
#Override
public String getUsername(Context ctx) {
...
authService.getAuthenticatedUser();
...
}
public void setAuthService(AuthService authService) {
this.authService = authService;
}
...
}
And my Spring configuration includes:
<context:component-scan base-package="controllers"/>
<bean id="authService" class="com.my.auth.class.AuthServiceClass" />
<bean class="play.mvc.Security$AuthenticatedAction" scope="prototype" />
In summary, spring doesn't seem to be injecting properties into my Sercuirty.Authenticator. How do you configure this correctly?

Resources