When using XML-based configuration for service-activator you can exclude the method as follows:
<service-activator input-channel="incomingCustomerChannel" output-channel="outgoingCustomerChannel" ref="customerService" />
This will cause the SI framework to choose the target method in customerService based on the payload. How can I achieve the same functionality using DSL and Java config?
At present I have the following:
#Bean
public IntegrationFlow customerRequestFlow(ConnectionFactory connectionFactory) {
return IntegrationFlows.from((MessagingGateways g) -> g.jms(connectionFactory)
.correlationKey("JmsCorrelationID")
.destination("customer_incoming.queue"))
.handle("customerService", "addCustomer")
.get();
}
The service activator is defined as:
#Component
public class customerService {
#ServiceActivator
public AddCustomerResponse addCustomer(AddCustomerRequest addCustomerRequest) {
// add customer
}
}
I have extended the activator to add a deleteCustomer method as follows:
#Component
public class customerService {
#ServiceActivator
public AddCustomerResponse addCustomer(AddCustomerRequest request) {
// add customer
}
#ServiceActivator
public DeleteCustomerResponse deleteCustomer(DeleteCustomerRequest request) {
// delete customer
}
}
I cannot simply remove the , "addCustomer" from .handle("customerService", "addCustomer") as methodName is mandatory. Is it possible to achieve this in Java config / DSL?
You can use the same .handle() using null for method name:
.handle("customerService", "addCustomer")
Or starting with version 1.1 you can use a new version of that method:
#Autowired
private CustomerService customerService;
....
.handle(this.customerService)
Both variants do exactly the same what you have with just ref for <service-activator>.
Related
I've already read these questions and none of them worked:
Spring boot MVC - Unable to Autowire Repository in the service class
Why can't #Autowired a JPA repository - Spring boot + JPA
JpaRepository getting Null at service class
And also this one: https://www.baeldung.com/spring-autowired-field-null
Unfortunately, none of them worked.
What I have is:
Service interface:
#Service
public interface DayTradeService {
public List<DayTrade> getDayTrades(List<NotaDeCorretagem> corretagens);
}
Service Implementation:
public class DayTradeServiceImpl implements DayTradeService {
#Autowired
private DayTradeRepository dayTradeRepository;
#Override
public List<DayTrade> getDayTrades(List<NotaDeCorretagem> corretagens) {
// Several lines of code and some of them is trying to use dayTradeRepository.
}
}
My DayTradeRepository:
#Repository
public interface DayTradeRepository extends JpaRepository<DayTrade, Integer> {}
Inside my DayTradeController (annotated with #Controller), I can use a dayTradeRepository with #Autowired. But inside a service class, I cannot use. I get this message:
Cannot invoke "meca.irpf.Repositories.DayTradeRepository.getDayTrades()" because "this.dayTradeRepository" is null"
How can I make it possible?
EDIT after I accepted Nikita's answer:
I didn't post the Controller code, but it didn't have the #Autowired for the service class DayTradeServiceImpl. That was the point I was missing. After Nikita pointing that, I could solve the problem.
You not need create new object. You have to call like this:
#Controller
#RequestMapping("/test")
public class TestController {
#Autowired
private DayTradeServiceImpl dayTradeService;
#GetMapping(value = "/get")
public void getTrades() {
dayTradeService.getDayTrades(...);
}
}
And set annotation #Service for DayTradeServiceImpl.
#Service
public class DayTradeServiceImpl implements DayTradeService {
#Autowired
private DayTradeRepository dayTradeRepository;
#Override
public List<DayTrade> getDayTrades(List<NotaDeCorretagem> corretagens) {
// Several lines of code and some of them is trying to use dayTradeRepository.
}
}
Spring framework use inversion of control, which has container for beans. For detect beans use annotation like: #Service, #Component, #Repository.
Let's say I have below setup, one interface I have has one method addTaxTrans():
public interface TaxTransInterface {
Response<Map<String, Object>> addTaxTrans(Long sessionId, TaxMap taxMap);
}
I have two classes implemented with this interface.
First impementation for client1
#Component
public class Client1TaxImpl implements TaxTransInterface {
#Override
public Response<Map<String, Object>> addTaxTrans(Long sessionId, TaxMap taxMap) {
// Common code + client 1 customization code
}
}
Second implementation for client 2
#Component
public class Client2TaxImpl implements TaxTransInterface {
#Override
public Response<Map<String, Object>> addTaxTrans(Long sessionId, TaxMap taxMap) {
// Common code + Client 2 customization code
}
}
Below is the service implementation, here I have autowired TaxTransInterface and calling addTaxtrans method:
#Service
public class TaxSerImpl implements TaxSer {
#Autowired
private TaxTransInterface taxTransInterface;
#Override
#Transactional(rollbackFor = Exception.class)
public Response<Map<String, Object>> addTax(TaxReq taxReq) {
// Calling Trans Function
return taxTransInterface.addTaxTrans(taxReq.getSessionId(),
taxReq.getTaxMap());
}
}
As of now I am not able to run the project getting below error:
Field taxTransInterface required a single bean, but 2 were found:
I know this error comes because two implementations I have for interface TaxTransInterface
So do we have any option like dynamically when I run application by below command for profile client1:
java -jar -Dspring.profiles.active=client1 sbill-0.0.1-SNAPSHOT.war
then dynamically Client1TaxImpl should get inject and when run application for client2 then Client2TaxImpl should get injected.
Any suggestions?
Thanks in advance.
Annotate your #Component class with #Profile("profilename") so the component will be injected based on the profile.
I'm using Spring Boot with a thrift server, and I have two #Configuration class with two bean generation method, and the code is as following:
#Configuration
public class EagleBeanCreator {
#Bean(destroyMethod = "destroy")
public EagleRestClient build() {
EagleRestClient client = new EagleRestClient();
// some set values code
return client;
}
}
And another one:
#Configuration
public class EagleServiceBuilder {
#Autowired
private EagleRestClient eagleProxy;
#Bean
public EagleService eagleService() {
EagleService service = new EagleService();
System.out.println(eagleProxy);
service.setEagleProxy(eagleProxy);
return service;
}
}
But when I run spring-boot:run, it print out null for "System.out.println(eagleProxy);"
Why?
=========================UPDATE=============================
I know setter injection or constructor injection works.
You may want to try this out.
#Configuration
public class EagleServiceBuilder {
#Bean
public EagleService eagleService(EagleRestClient eagleProxy) {
EagleService service = new EagleService();
System.out.println(eagleProxy);
service.setEagleProxy(eagleProxy);
return service;
}
}
My guess is that the way you currently implement doesn't indicate a dependency between the EagleService and EagleRestClient. So your current implementation leads to random initialization order between the two beans. The modified version tells Spring "Hey, my EagleService depends on EagleRestClient. Please initialize EagleRestClient before EagleService.
Because the order to load EagleBeanCreator and EagleServiceBuilder is not definite. You can use #Order or #ConditionalOnClass to make sure EagleBeanCreator initialize first.
Because the #Configuration bean are initialized in the same phase of bean lifecycle. I don't remember them clearly but something like:
Configurations -> Components -> Services
With the beans in the same phase, if they depend on each other, you should declare the load order by some #Conditional or #Order
Add #DependsOn("eagleRestClient") annotation on the definition of EagleService.
#DependsOn("eagleRestClient")
#Bean
public EagleService eagleService() {
EagleService service = new
EagleService();
System.out.println(eagleProxy);
service.setEagleProxy(eagleProxy);
return service;
}
Spring will then first create rest client then the eagle service.
First, you need to get the spring container through ApplicationContextAware try
ApplicationContext.getBean(EagleRestClient.class)
How to intercept #RestController methods using MethodInterceptor in SpringBoot?
Prior to using springboot, I have a simple Interceptor that logs the execution time of a bean method. Simply intercepts all spring bean methods through a default proxy definition.
#Component
public class MethodTimer implements MethodInterceptor {
#Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
final StopWatch stopWatch = new StopWatch();
stopWatch.start(methodInvocation.getMethod().toGenericString());
try {
return methodInvocation.proceed();
}
finally {
stopWatch.stop();
System.out.println(stopWatch.prettyPrint());
}
}
}
The spring configuration where com.mypackages contains the beans and the MethodInterceptor implementation.
<context:component-scan base-package="com.mypackages" />
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator">
<property name="proxyTargetClass" value="true"/>
</bean>
The configuration above is loaded via
#ContextConfiguration("/application-context.xml")
Method executions are logged, everything seems to be working, life is good.
Moving to SpringBoot
I use the same code, switched to annotations (eliminating the *.xml) configuration
#SpringBootApplication(scanBasePackages = { "com.mypackages" })
#EnableAutoConfiguration
#EnableAspectJAutoProxy(proxyTargetClass=true)
Added a constructor to the MethodTimer with System.out.println() to make sure that the Interceptor has been loaded by spring boot
public MethodTimer() {
System.out.println("MethodTimer - Constructor");
}
And yes, it was loaded and created as "MethodTimer - Constructor" is found in the console logs.
However, none of the #RestController methods are intercepted. Below is a simple Rest Controller
#RestController
#RequestMapping("/test")
public class HelloWorldService {
#RequestMapping(method = RequestMethod.GET)
public String sayHello() {
System.out.println("Hello World!");
return "Hello World!";
}
}
Even tried creating a pure spring bean via #Component and #Autowired it in the #RestController to see if that pure spring bean is intercepted, but it was not intercepted as well.
A simple Test service bean. The test() method should be intercepted.
#Component
public class TestService {
public void test() {
System.out.println("TestService.test()");
}
}
Revised RestController
#RestController
#RequestMapping("/test")
public class HelloWorldService {
#Autowired
private TestService testService;
#RequestMapping(method = RequestMethod.GET)
public String sayHello() {
testService.test();
return "Hello World!";
}
}
Notes
The MethodTimer was loaded as the constructor was called showing the System.out.println log in the console, it seems however spring boot did not automatically determine that this bean/component is implementing MethodInterceptor.
The simple Spring Bean annotated with #Component bean was not intercepted.
The Rest Controller annotated with #RestController was not intercepted.
I have tried adding #Component, #Service in the RestController, it did not work.
I have tried tried #EnableAutoConfiguration, adding spring.aop.* configurations in the application.properties, did not work.
Tried using SpringBoot version 1.5.4.RELEASE, does not work.
I know I can always try to use Aspect as shown in the spring-boot-sample-aop example: https://github.com/spring-projects/spring-boot/tree/master/spring-boot-samples/spring-boot-sample-aop
But not able to use previous spring code and configure it with springboot is just too lame. If MethodInterceptor and DefaultAdvisorAutoProxyCreator is not supported anymore in spring boot, it should have been deprecated
i am really confused with spring annotations.
where to use # Autowired, where class is # Bean or # Component,
i understand we cannot use
Example example=new Example("String");
in Spring
but how alone
#Autowired
Example example;
will solve the purpose?
what about Example Constructor ,how spring will provide String value to Example Constructor?
i went through one of the article but it does not make much sense to me.
it would be great if some one can give me just brief and simple explanation.
Spring doesn't say you can't do Example example = new Example("String"); That is still perfectly legal if Example does not need to be a singleton bean. Where #Autowired and #Bean come into play is when you want to instantiate a class as a singleton. In Spring, any bean you annotate with #Service, #Component or #Repository would get automatically registered as a singleton bean as long as your component scanning is setup correctly. The option of using #Bean allows you to define these singletons without annotating the classes explicitly. Instead you would create a class, annotate it with #Configuration and within that class, define one or more #Bean definitions.
So instead of
#Component
public class MyService {
public MyService() {}
}
You could have
public class MyService {
public MyService() {}
}
#Configuration
public class Application {
#Bean
public MyService myService() {
return new MyService();
}
#Autowired
#Bean
public MyOtherService myOtherService(MyService myService) {
return new MyOtherService();
}
}
The trade-off is having your beans defined in one place vs annotating individual classes. I typically use both depending on what I need.
You will first define a bean of type example:
<beans>
<bean name="example" class="Example">
<constructor-arg value="String">
</bean>
</beans>
or in Java code as:
#Bean
public Example example() {
return new Example("String");
}
Now when you use #Autowired the spring container will inject the bean created above into the parent bean.
Default constructor + #Component - Annotation is enough to get #Autowired work:
#Component
public class Example {
public Example(){
this.str = "string";
}
}
You should never instantiate a concrete implementation via #Bean declaration. Always do something like this:
public interface MyApiInterface{
void doSomeOperation();
}
#Component
public class MyApiV1 implements MyApiInterface {
public void doSomeOperation() {...}
}
And now you can use it in your code:
#Autowired
private MyApiInterface _api; // spring will AUTOmaticaly find the implementation