I am using a Spring 5 MVC application. I am trying to get a pure java configuration going. I notice that my logging is not working. I have this in my application.properties:
logging.level.org.springframework.web=ERROR
logging.level.org.springframework.security=ERROR
logging.level.org.hibernate.SQL=DEBUG
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE
Now I am not using application.properties of course, so how do I set this in a pure Java way in one of my #Configuration classes?
If you actually want to get a pure java logger configuration, you can setup it like this:
public class LoggingInitializer implements ApplicationContextInitializer {
#Override
public void initialize(ConfigurableApplicationContext applicationContext) {
//suppose you use default logback (ch.qos.logback.classic.LoggerContext)
LoggerContext c = (LoggerContext) LoggerFactory.getILoggerFactory();
c.getLogger("ru.varren").setLevel(Level.DEBUG);
c.getLogger("org.springframework.web").setLevel(Level.ERROR);
c.getLogger("org.springframework.security").setLevel(Level.ERROR);
c.getLogger("org.hibernate.SQL").setLevel(Level.DEBUG);
}
}
And then init it in main before the app starts.
public class Main {
public static void main(String[] args){
new SpringApplicationBuilder(Main.class)
.initializers(new LoggingInitializer())
.run(args);
}
}
Also take a look at this answer: https://stackoverflow.com/a/20521500/1032167
Related
I have project setup using Spring boot that loads individual components on startup. Each individual packages contain its own datasource, processes, etc. I can simply use this and it works fine
#SpringBootApplication(scanBasePackages = {
"com.package1",
"com.package2",
"com.package3"
})
public class Application extends SpringBootServletInitializer{
public static void main(String[] args){
SpringApplication.run(Application.class,args)
}
}
But currently, the number of indiviual projects are getting bigger. Is it possible to put the list of the components / packages to scan in an external properties file or spring vault? I'm not sure how to retrieve it, and is it possible to retrieve the properties before the boot?
Edit:
Currently I tried this:
#Import(AppConfig.class)
public class Application extends SpringBootServletInitializer{
public static void main(String[] args){
SpringApplication.run(Application.class,args)
}
}
#Configuration
#ComponentScan(basePackages = {$app.packages})
#EnableAutoConfiguration
public class AppConfig {
}
//in my properties file
app.packages = ["com.package1","com.package2","com.package3"]
but its not working
You are on right track but couple of minor mistakes, specify the packages by common separated in yml or properties file
app.packages = com.package1,com.package2,com.package3
Then use Spring Expression Language in #ComponentScan annotation
#ComponentScan(basePackages = {"${app.packages}"})
This can be done using a static string constant. I tried following and it is working.
ScanBasePackageTestApplication is in 3rd package other than "test.packageOne, test.packageTwo" packages. Then I tried to autowire single class from each of test.packageOne and test.packageTwo into class from main package and it worked fine.
#Configuration
#SpringBootApplication(scanBasePackages = PackagesScanMetaData.PACKAGES_TO_SCAN)
public class ScanBasePackageTestApplication {
public static void main(String[] args) {
SpringApplication.run(ScanBasePackageTestApplication.class, args);
}
}
public class PackagesScanMetaData {
public static final String PACKAGES_TO_SCAN = "test.packageOne, test.packageTwo";
}
In this case you can manage all the to be scanned package list in PackagesScanMetaData class. Hope this helps.
This is a similar but further question with how to run/turn off selective tests based on profiles in spring boot.
I know the #IfProfileValue annotation provides the ability to enable test based on some conditions, but the properties it get are from System.properties and the spring.profiles.active is not in it.
I also know we can use #ProfileValueSourceConfiguration to customise the ProfileValueSource like below:
Test
#RunWith(SpringRunner.class)
#SpringBootTest
#ProfileValueSourceConfiguration(value = SpringProfileValueSource.class)
#IfProfileValue(name = "spring.profiles.active", value = "test")
public class MyTest {
// some tests
}
Custom ProfileValueSource
public class SpringProfileValueSource implements ProfileValueSource {
#Override
public String get(String key) {
Environment environment = StaticSpringContext.applicationContext.getEnvironment();
return environment.getProperty(key);
}
}
Since the SpringProfileValueSource will be created outside of Spring, so I created the following class to get Spring context:
StaticSpringContext
#Configuration
public class StaticSpringContext implements ApplicationContextAware {
public static ApplicationContext applicationContext;
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
StaticSpringContext.applicationContext = applicationContext;
}
}
However, seems all the properties check happens before Spring get started, so the applicationContext in StaticSpringContext is actually null when I use it in SpringProfileValueSource.
I thought it was a common situation to enable tests based on spring profiles, but I did many search and still don't know how to do it. Any ideas? With many thanks.
I'm trying to create a demo AOP application but it just does not work right.
I read through all tutorials and got it working with #RestController but as I tried it with a plain java spring driven application I just can't get it to work. Please review my files and tell me where my mistake lies in.
Application Class
#SpringBootApplication
#ComponentScan("com.xetra.experimental")
#EnableAspectJAutoProxy
public class AoptryoutnowebApplication {
public static void main(String[] args) {
SpringApplication.run(AoptryoutnowebApplication.class, args);
DefaultClassToAspectImpl defaultClassToAspectImpl = new DefaultClassToAspectImpl();
defaultClassToAspectImpl.doStuff();
}
}
ClassToAspect Interface
public interface ClassToAspect {
void doStuff();
}
ClassToAspect Implementation
#Component
public class DefaultClassToAspectImpl implements ClassToAspect {
#FooAnnotation
public void doStuff(){
System.out.println("DoStuff!");
}
}
Annotation for Pointcut
public #interface FooAnnotation {
}
Aspect Class
#Aspect
public class FooAspect {
#Pointcut("#annotation(FooAnnotation)")
public void methods(){
}
#Before("methods()")
public void doAspect(){
System.out.println("FooAspect before");
}
}
Try this:
replace #EnableAspectJAutoProxy with #EnableAspectJAutoProxy(proxyTargetClass = false)
change pointcut to
#Pointcut("execution (* your.package..*.*(..)) && #annotation(fooAnnotation))")
The problem is you are using a non Spring managed instance by doing new DefaultClassToAspectImpl(). Spring AOP only works for Spring managed beans, because by default Spring AOP is proxy based.
So instead of doing new DefaultClassToAspectImpl() you should be obtaining the instance from the ApplicationContext. When using Spring Boot the SpringApplication.run call returns an ApplicationContext. Here you can use one of the getBean methods to obtain the instance you want.
ApplicationContext ctx = SpringApplication.run(AoptryoutnowebApplication.class, args);
ClassToAspect bean = getBean(ClassToAspect.class);
bean.doStuff();
This way you get the Spring managed
I'm using Spring (without spring-boot). I want to build standalone application that can be run with default configuration (logback.xml and application.properties in resource folder) or with -Dconfig.folder=/path/to/custom/external/directory
(logback.xml and application.properties in /path/to/custom/external/directory). When application will be run with -Dconfig.folder param AppConfig should load both logback and properties from external directory.
Is there anyway to make external folder act like a resource folder?
If not, what is a common solution for this?
My current implementation (using default resource folder only):
App.java
public class App {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
SampleAction p = context.getBean(SampleAction.class);
p.performTask();
}
}
AppConfig.java
#ComponentScan
#PropertySource("classpath:application.properties")
class AppConfig {
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
}
SampleAction.java
#Component
public class SampleAction {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
#Value("${sample.prop}")
private String sampleProp;
public void performTask(){
logger.debug(sampleProp);
}
}
logback.xml and application.properties are not relevant to the problem
Unlike the other answer suggests, if you use file prefix in #PropertySource, you're screwed because it won't be able to load the default application.properties from the jar. What you should do is the following:
#PropertySource("${config.folder:'classpath:'}/application.properties")
public class AppConfig
For logback.xml:
#Value("${config.folder}:")
private String configFolder;
InputStream = Optional.of(new ClassPathResource(configFolder + "/logback.xml"))
.filter(r -> r.exists())
.orElse(new ClassPathResource("classpath:/logback.xml"))
.getInputStream();
In both cases, I gave preference to the command line argument over the default packaged files. Of course, I didn't compile the above, so there may be typos or minor errors, but you get the idea.
Edit:
Since OP claims to not understand where to run the above code -
public class AppConfig {
#PostConstruct
void init() {
// init logback here
}
}
For log4j.xml
-Dlog4j.configuration=C:\neon\log4j.xml as VM argument
In main() method:
String filename = System.getProperty("log4j.configuration");
DOMConfigurator.configure(filename);
For external properties file:
-Dext.prop.dir=C:\neon as VM argument
Change in your AppConfig class will be like
#PropertySource("file:///${ext.prop.dir}/application.properties")
public class AppConfig{
}
Run App class with VM arguments as below and both file will be use from external location
-Dlog4j.configuration=C:\neon\log4j.xml -Dext.prop.dir=C:\neon
I am using spring boot application mvc with graphDb (Neo4j) as my database.
And I have problem when I have to do internationalization for my app.
I have this code on my application.java
public class Application extends Neo4jConfiguration {
#Autowired
GraphDatabase graphDatabase;
#Bean
GraphDatabaseService graphDatabaseService() {
return new GraphDatabaseFactory().newEmbeddedDatabase("my-graphdb");
}
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
When I tried to implement internationalization, the tutor says that I need to implement:
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(localeChangeInterceptor());
}
This code above need the class is extended by WebMvcConfigurerAdapter.
This is the problem, I didn't use WebMvcConfigurerAdapter so I cannot add the method above.
Do I have another option to make my internationalization work well with Neo4jConfiguration?
I just found out how to make it work.
I just have to add new file that extend WebMvcConfigurerAdapter and put the addInterceptors module into that new file.
Which tutorial are you referring to?
you can also create your own Neo4jConfiguration subclass and #Import it onto your boot application context