How to proper create bean Spring using annotations Bean and ComponentScan? - java

Main:
#SpringBootApplication
#ComponentScan(basePackageClasses = Application.class)
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Test class:
public class Test {
#Bean
public Test test(){
return new Test();
}
}
and when I'm trying to autowire it then i got this exception:
***************************
APPLICATION FAILED TO START
***************************
Description:
Field test in TestWithAutowire required a bean of type 'Test' that could not be found.
Action:
Consider defining a bean of type 'rcms.backend.exception.Test' in your configuration.
Process finished with exit code 1
There is something hat I'm doing wrong, but I can't find it out.

You can create a new configuration, let's say SpringConfiguration,
package my.pkg.config;
#Configuration
public class SpringConfiguration {
#Bean
public Test test(){
return new Test();
}
}
In your Application class, you can add the #ComponentScan annotation with the base packages where you would like Spring to scan for classes,
#SpringBootApplication
#ComponentScan(basePackageClasses = {"my.pkg.config", "my.pkg.example"})
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Now you can autowire Test in any Spring component. For example,
package my.pkg.example;
#Component
public class TestExample {
#Autowired
private Test tst;
}

Related

How to include multiple #SpringBootApplication by #Profile?

I would like to define multiple #SpringBootApplication configurations that should load different packages. So that I can only load certain parts of the application, depending on the -Dspring.profiles.active= property.
Eg, the following MyApp1 startup class should only auto load classes under com.myapp.config1 subpackages:
package com.myapp.config1
#SpringBootApplication
#Profile("app1")
public class MyApp1 {
public static void main(String[] args) {
SpringApplication.run(MyApp1.class, args);
}
}
And another package aside:
package com.myapp.config2
#SpringBootApplication
#Profile("app2")
public class MyApp2 {
public static void main(String[] args) {
SpringApplication.run(MyApp2.class, args);
}
}
Problem: I cannot have multiple main() in multiple classes, as I lateron want to run my app with mvn spring-boot:run. How could this be solved?
If you want to load different packages depending on a profile you should instead define different configuration classes that are annotated with different #ComponentScan annotations.
#Configuration
#ComponentScan("bar.foo")
#Profile("app1")
public class loadApp2 {
}
#Configuration
#ComponentScan("foo.bar")
#Profile("app2")
public class loadApp1 {
}
This is actually the recommended way of setting up configuration and is called "slicing" and is documented in the spring boot docs
If I understand your question properly, then you want to run different class based on profiles, then you can have profile like below:
#Configuration
#ComponentScan("abc")
#Profile("app1")
public class MyApp1 {
//
}
#Configuration
#ComponentScan("xyz")
#Profile("app2")
public class MyApp2 {
//
}
Now in your SpringBootapplication:
#SpringBootApplication
public class SpringApp {
#Autowired
Environment env;
public static void main(String[] args) {
if (Arrays.asList(env.getActiveProfiles()).contains("app1"))
SpringApplication.run(MyApp1.class, args);
else
SpringApplication.run(MyApp2.class, args);
}
}
Could solve it as follows.
package com.myapp
#SpringBootApplication(scanBasePackages = "com.myapp.config")
public class MyApp {
public static void main(String[] args) {
SpringApplication.run(MyApp.class, args);
}
}
Which loads config:
package com.myapp.config
#Configuration
#Profile("app1")
#ComponentScan(basePackages = "com.myapp.app1")
public class App1Config {
//only load classes from app1 package
}
#Configuration
#Profile("app2")
#ComponentScan(basePackages = "com.myapp.app2")
public class App2Config {
//only load classes from app2 package
}
You could specify the main class in the spring boot plugin configuration. I am not sure if you are using gradle or maven... so cant tell you the exact config.
https://docs.spring.io/spring-boot/docs/current/maven-plugin/reference/htmlsingle/#goals-repackage-parameters-details-mainClass

Spring boot dependency injection of an interface

I have 2 spring boot microservice let's say core and persistence. where persistence has a dependency on core.
I have defined an interface in core whose implementation is inside persistence as below:
core
package com.mine.service;
public interface MyDaoService {
}
Persistence
package com.mine.service.impl;
#Service
public class MyDaoServiceImpl implements MyDaoService {
}
I am trying to inject MyDaoService in another service which is in core only:
core
package com.mine.service;
#Service
public class MyService {
private final MyDaoService myDaoService;
public MyService(MyDaoService myDaoService) {
this.myDaoService = myDaoService;
}
}
while doing this i am getting this weird error:
***************************
APPLICATION FAILED TO START
***************************
Description:
Parameter 0 of constructor in com.mine.service.MyService required a bean of type 'com.mine.service.MyDaoService' that could not be found.
Action:
Consider defining a bean of type 'com.mine.service.MyDaoService' in your configuration.
can anyone explain me why ?
NOTE: i have already included com.mine.service in componentscan of springbootapplication as below
package com.mine.restpi;
#SpringBootApplication
#EnableScheduling
#ComponentScan(basePackages = "com.mine")
public class MyRestApiApplication {
public static void main(String[] args) {
SpringApplication.run(MyRestApiApplication.class, args);
}
}
Try adding the #Service annotation to your impl classes and the #Autowired annotation to the constructor.
// Include the #Service annotation
#Service
public class MyServiceImpl implements MyService {
}
// Include the #Service annotation and #Autowired annotation on the constructor
#Service
public class MyDaoServiceImpl implements MyDaoService {
private final MyService myService ;
#Autowired
public MyDaoServiceImpl(MyService myService){
this.myService = myService;
}
}
As stated in the error message hint: Consider defining a bean of type 'com.mine.service.MyDaoService' in your configuration to solve this problem you can define in your package com.mine a configuration class named MyConfiguration annotated with #Configuration including a bean named myDaoService like below:
#Configuration
public class MyConfiguration {
#Bean
public MyDaoService myDaoService() {
return new MyDaoServiceImpl();
}
}
Try the following, move MyRestApiApplication class to com.mine package and remove #ComponentScan annotation.
package com.mine;
#SpringBootApplication
#EnableScheduling
public class MyRestApiApplication {
public static void main(String[] args) {
SpringApplication.run(MyRestApiApplication.class, args);
}
}

How to resolve placeholder value in SpringBoot

Kindly help with accessing values from yaml file in Sprint Boot. I am getting error as below. I am able to access value of filepath1 variable in AppConfig class but not sure why its giving the error.
Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'filepath1' in value "${filepath1}"
at org.springframework.util.PropertyPlaceholderHelper.parseStringValue(PropertyPlaceholderHelper.java:178)
at org.springframework.util.PropertyPlaceholderHelper.replacePlaceholders(PropertyPlaceholderHelper.java:124)
at org.springframework.core.env.AbstractPropertyResolver.doResolvePlaceholders(AbstractPropertyResolver.java:239)
at org.springframework.core.env.AbstractPropertyResolver.resolveRequiredPlaceholders(AbstractPropertyResolver.java:210)
My main class is as follows
#SpringBootApplication
public class DemoApplication {
public static void main(String[] args)
{
System.out.println("Starting ");
SpringApplication.run(DemoApplication.class, args);
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(DemoApplication.class);
Employee employee = applicationContext.getBean(Employee.class);
System.out.println("Exiting ");
}
}
Config class is as follows
#Slf4j
#Configuration
#ComponentScan("com.vish.springbootdemo.demo")
public class AppConfig
{
#Value("${filepath1}")
private String file1;
#Bean
public Employee employee()
{
System.out.println("file1 is " + file1);
return new Employee();
}
}
Here is the application.yml
filepath1: "vish"
The problem is that in the main method, you are creating your own application context:
ApplicationContext applicationContext =
new AnnotationConfigApplicationContext(DemoApplication.class);
This will be completely separate from the application context that Spring Boot creates for you, and won't have the configuration properties from application.yml in it.
Instead of doing this, use the application context that Spring Boot provides. Even better: Don't explicitly lookup a bean in the application context, but let Spring Boot autowire the bean for you.
Something like this:
#SpringBootApplication
public class DemoApplication implements CommandLineRunner {
#Autowired
private Employee employee;
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
#Override
public void run(String... args) throws Exception {
System.out.println("Employee: " + employee);
}
}
AppConfig:
#Configuration
public class AppConfig {
#Value("${filepath1}")
private String file1;
#Bean
public Employee employee() {
System.out.println("file1 is " + file1);
return new Employee();
}
}
Start your spring boot application like this:
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
Resources folder should contain application.yml.
filepath1: vish
Inject your bean with #Autowired
#Component
class AnotherComponent {
#Autowired Employee employee;
}

Unable to Autowire

Using Spring Initializer to create a simple Spring boot. I am only choosing DevTools under the options available.
After creating the project, without making any changes to it, able to run the program fine.
Now when I try to do some Autowiring in the project, it simply doesn't work. I don't get it. Been looking all over previous questions here which has resolutions for it but none works plus there is nothing complex about what I am doing in my case as follows. Please advice what I am missing.
#SpringBootApplication
public class DemoApplication {
// #Autowired
// private static Maker maker; // Stopped using this cos I wanted to check if the autowiring is not working in this class only or anywhere. Turns out it is anywhere.
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
Maker maker = new Maker();
maker.printName(); // Fails cos of ServiceHelper Autowiring
}
}
#Service
public class Maker {
#Autowired
private ServiceHelper serviceHelper;
public void printName(){
System.out.println("This is from the method body itself.");
System.out.println("Auto wiring works cos I got this -> " + serviceHelper.help());
}
}
#Component
public class ServiceHelper {
public String help(){
return "...FROM HELPER...";
}
}
StackTrace
Exception in thread "restartedMain"
java.lang.reflect.InvocationTargetException at
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497) at
org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49)
Caused by: java.lang.NullPointerException at
com.example.demo.services.Maker.printName(Maker.java:15) at
com.example.demo.DemoApplication.main(DemoApplication.java:17) ... 5
more
If you create any bean using new keyword that bean will not added to Spring Application Context, and this is one way to #Autowire static beans
#SpringBootApplication
public class DemoApplication {
#Autowired
private static Maker maker;
#Autowired
private Maker tMaker;
#PostConstruct
public void init() {
DemoApplication.maker = tMaker;
}
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
maker.printName();
}
}
or you can do Autowire using Constructor the instance of Maker is injected as an argument to the constructor when DemoApplication is created
#Autowired
public DemoApplication(Maker maker) {
DemoApplication.maker = maker;
}
or you can use #Autowired on setter method, the setter method is called with the instance of Maker when DemoApplication is created
#Autowired
public void setMaker(Maker maker) {
DemoApplication.maker = maker
}
You create yourself an instance, its ServiceHelper does not get autowired by Spring:
Maker maker = new Maker();
You can access bean via ApplicationContext:
#SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
ApplicationContext cts = SpringApplication.run(DemoApplication.class, args);
Maker maker = ctx.getBean(Maker.class);
maker.printName();
}
}
When you use new Maker() you are not using the bean Spring created for you and as a result the the object you have is uninitialized as dependencies are not injected.
You need to get the bean which the Spring framework created, like I did below as directly you cannot autowire static fields:
#SpringBootApplication
public class DemoApplication {
private static Maker maker;
#Autowired
public void setMaker(Maker maker) {
DemoApplication.maker = maker;
}
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
maker.printName();
}
}

import package Bean for annotation in java

I use the #Bean annotation in java with spring-boot and I can not find the module I need to import.
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Bean
public PersistenceAnnotationBeanPostProcessor persistenceBeanPostProcessor() {
return new PersistenceAnnotationBeanPostProcessor();
}
}

Categories

Resources