Identifying Start-Class during runtime in spring boot - spring

I am trying to identify a way to know the name of the Main-Class that started SpringBoot.
e.g.
#SpringBootApplication
public class SampleApplication {
public static void main(String[] args) {
SpringApplication.run(SampleApplication.class, args);
}
#RestController
public class SampleController
{
#GetMapping("/hello")
pubic String sayHello()
{
System.out.println("Need start class name: "+System.getProperty("sun.java.command"));
return "hello";
}
}
}
When I run the springboot using java -jar myappname.jar ,the System.getProperty("sun.java.command") returns org.springframework.boot.loader.JarLauncher
Can anyone advise, how can I get the name of actual run class. I have tried specifying the start-class attribute in the manifest.mf. It still gave me org.springframework.boot.loader.JarLauncher as the start-class.

You should be able to #Autowire in the ApplicationContext and then do context.getBeansWithAnnotation(SpringBootApplication.class).values().toArray()[0].getClass().getName(), which will give you the first (and presumably only) bean in the context annotated with #SpringBootApplication

Related

Not getting values from application.properties in SpringBoot application

I created a simple SpringBoot application using "http://start.spring.io" Spring Initializr. I am using JDK 8 and Spring 2.6.6.
I opened an application in IntelliJ and was able to build it and run it. I also added "application.properties" as my resource where I defined a property :
application.baseurl=/responsiblityViewer/api
in my DemoApplication.java :
public class DemoApplication {
#Value("${application.baseurl}")
public static String baseUrl;
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
System.out.println("Test Application baseUrl : " + baseUrl);
}
}
The output is NULL.
I also tried to use "application.yml" where I defined :
application:
baseurl: /responsiblityViewer/api
and still "application.baseurl" is not getting injected. What am I doing wrong here?
There's a lot to dissect here.
First, you can't inject a value into a static property.
Second, you will not be able to reference that property from a static main method as the bean hasn't been constructed yet.
If you read up on the spring bean lifecycle it will help you to understand this, the injection occurs after instantiation.
You can observe this behavior if you change your variable definition to
public String baseUrl;
and add this method
#PostConstruct
public void printIt() {
log.debug(baseUrl);
}

Spring boot #ConfigurationProperties not working

I'm using #ConfigurationProperties for auto configuration of properties. My code is working in IDE. But when I run the jar in command line, it is not working.
Configuration class:
#Configuration
#ConfigurationProperties(prefix="location")
public class Location {
private String base;
public String getBase() {
return base;
}
public void setBase(String base) {
this.base = base;
}
}
Main class:
#SpringBootApplication
#EnableConfigurationProperties(Location.class)
#EnableAutoConfiguration
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
application.yml:
location:
base: c:\test
If I autowire Location class, I see an instance created. But there is not property set. The code is not entering setBase() method.
The application prints this in the console.
AutowiredAnnotationBeanPostProcessor : JSR-330 'javax.inject.Inject'
annotation found and supported for autowiring
Make sure that application.yml file is in the root of your classpath, usually it's put in the resources folder.
The fact that the setBase() method is not called suggests that your application.yml file is not being found. Spring looks in the root of your classpath for the application.yml file.
The comment from M. Deinum is correct saying that your duplicated annotations will result in 2 spring beans for Location class. However, as you say you managed to autowire the bean without getting an error it suggests that your Location class isn't in a package that is found by spring when it's scanning for beans. If there were 2 beans then you'd get an error when you autowired it. By default spring will scan use the package where the #SpringBootApplication is as the base. It will then look in this package and all sub packages.
If your package structure is like this...
myapp.main
Application.java
myapp.config
Location.java
Then you need to add scanBasePackages="myapp" to the #SpringBootApplication annotation.
Also change your main class and remove the #Enable.. annotations. i.e.:
#SpringBootApplication(scanBasePackages="myapp")
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
As nothing worked with yaml, I had to change to property file and use
#PropertySource({"classpath:application.properties"})
for the spring to identify the properties file

Replace Beans.xml configuration in Spring

How can I replace beans.xml file for testing purposes?
I use
#SpringBootApplication
#ImportResource("classpath:Beans.xml")
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
to init class, but in my testing class
#RunWith(SpringRunner.class)
#SpringBootTest
public class ArrayCointainerTest {
I'd like to use another one.
Any idea for this?
Define a separate configuration class which has you beans xml imported and annotate that with #TestConfiguration. Spring boot automatically pick this up as your test configuration
Detecting test configuration

spring mvc + spring aop + aspectj

I struggle to use aspect in Spring MVC project.
Method that is a pointcut is running fine, but without advise.
Here is class, that starts whole spring boot and that is root of spring context:
#Lazy
#SpringBootApplication
#EnableAspectJAutoProxy(proxyTargetClass=true)
#Configuration
public class MainSpringBootClass{
public static void main(String[] args)
{
SpringApplication.run(MainSpringBootClass.class, args);
}
}
Here is class with method, that is pointcut.
#Component
#Log
#Aspect
#EnableAspectJAutoProxy(proxyTargetClass=true)
public class MyExampleClass
{
public void example()
{
System.out.println("example");
}
}
And here is my aspect:
#Aspect
#Component
#EnableAspectJAutoProxy(proxyTargetClass=true)
public class MyAspect implements MethodBeforeAdvice
{
#Pointcut("execution(* com.example.MyExampleClass.example())")
public void asd()
{
// pointcut
}
#Before("asd()")
public void login()
{
System.out.println("im am logging in");
}
#Before("execution(* com.example.MyExampleClass.example())")
public void login2()
{
System.out.println("im am logging in2");
}
#Override
public void before(Method method, Object[] args, Object target) throws Throwable
{
System.out.println("aop before");
}
}
And here is my controller:
#RestController
#EnableAspectJAutoProxy(proxyTargetClass=true)
public class MyExampleController
{
private final MyExampleClass myExampleClass;
#Inject
public AdController(MyExampleClass myExampleClass)
{
this.myExampleClass = myExampleClass;
}
#RequestMapping("/")
public String index()
{
myExampleClass.example();
return "x";
}
}
As You can see, I have been trying to bruteforce correct result with annotations.
I have also seen on some website, that I need specific dependencies, so here are mine (pasting only those, related to aspects):
compile 'org.springframework:spring-aop:+'
compile 'org.aspectj:aspectjrt:+'
compile 'org.aspectj:aspectjweaver:+'
compile 'cglib:cglib:+'
compile 'cglib:cglib-nodep:+'
All dependencies have been successfully downloaded, project compiles and runs fine.
When I hit localhost:8080 then I see returned value "x", and inside logs I see "example".
However, I do not see any advices from spring aop nor aspectj - what am I doing wrong?
I am just using this project as sandbox to learn aspects, so I would be eager to learn, how to do it with each of Spring AOP and AspectJ.
The most important thing for me is to do it all without XML.
EDIT:
I have added simple constructor to MyAspect with println to check, if it is created (as it is normal spring bean with #Component after all) and it does - it is correctly created by spring.
EDIT 2:
IntelliJ IDEA tells me about methods login and login2: "This advice advices no method", but at the same time, I am able to jump (with control-click) from string, that is value in annotations to correct implementations.
All you should need is something like this:
#Aspect
#Component
public class MyAspect {
#Before("execution(* com.example.MyExampleClass.example(..))")
public void logBefore(JoinPoint pjp) throws Throwable {
System.out.println("before...");
}
}
You might have to replace all of the aspectJ dependencies with spring-boot-starter-aop .
Here's an example project that works (see RestControllerAspect.java):
https://github.com/khoubyari/spring-boot-rest-example

Spring Boot not using application.properties for spring.groovy.template.cache

I have a very simple Spring Boot application with classes detailed below.
My problem is with the application.properties file and how they get auto-configured. I'm trying to get Groovy Templates to update in dev by setting 'spring.groovy.template.cache: false', however this is not working. I added two more properties to see if the application.properties file was being read. The 'logging.level.org.springframework.web: ERROR' still results in INFO level messages printed to the console. However, some.prop is read correctly into the MyBean class on application start.
Is there a configuration declaration I'm missing for these properties?
src/main/resources/application.properties:
spring.groovy.template.cache: false
logging.level.org.springframework.web: ERROR
some.prop: bob
src/main/java/sample/MyBean.java:
#Component
public class MyBean {
#Value("${some.prop}")
private String prop;
public MyBean() {}
#PostConstruct
public void init() {
System.out.println("================== " + prop + "================== ");
}
}
and src/main/java/sample/Application.java:
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
and src/main/java/sample/com/example/MainController.java
#Controller
public class MainController {
#RequestMapping(value="/login", method = RequestMethod.GET)
public ModelAndView risk(#RequestParam Optional<String> error) {
return new ModelAndView("views/login", "error", error);
}
}
It seems you missing scanned your package "sample". Please make sure that you have scanned it.
#ComponentScan({
"sample" })
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Also, your application.properties is right. No problem with it.
It appears the solution was much simpler than I thought:
gradle bootRun
should be used to hot reload templates
gradle run does not work (all compiled classes are just built in build/ )

Resources