Should I use #Transactional using #EnableTransactionManagement? - spring

I've got a Spring Boot application. Everything works fine. I'm just trying to understand how does transaction manager work, because I have suspicion about my application. In particular, I'm a little confused about annotations.
Here is Application.java (main class):
#SpringBootApplication(exclude = ActiveMQAutoConfiguration.class)
#EnableScheduling
public class Application extends SpringBootServletInitializer
{
#Override
protected SpringApplicationBuilder configure (SpringApplicationBuilder builder) {
return builder.sources(Application.class);
}
public static void main(String[] args)
{
SpringApplication.run(Application.class, args);
}
}
config class DataConfig.java looks like:
#Configuration
#EnableTransactionManagement
#ComponentScan("com.pr.hotel")
#EnableJpaRepositories("com.pr.hotel")
#PropertySource("classpath:application.properties")
public class DataConfig
{
// code
}
I'm worry about #EnableTransactionManagement. What exactly does this annotation mean? Should I use #Transactional in this case (I don't)?

#EnableTransactionManagement does exactly what it says:
Enables Spring's annotation-driven transaction management capability,
similar to the support found in Spring's XML namespace.
Yes, you should still use #Transactional annotation on methods that you want to wrap in a transaction. In the following example the result of saveSomething() wouldn't be applied if maybethrowaneException() threw an exception. Be careful to use org.springframework.transaction.annotation.Transactional and not javax.transaction.Transactional.
The #Transactional annotation tells Spring to control when the data are flushed to the database (typically once the method successfully completes). Without the annotation the data would be flushed immediately.
It's a mechanism to prevent incomplete changes being written to the database when something goes wrong. Further reading: https://dzone.com/articles/how-does-spring-transactional
#Service
public class DataTransformer() {
#Transactional
public void doETL() throws Exception {
loadSomeEntities();
saveSomething();
maybethrowanException();
saveSomethingElse();
}
}

Related

#Autowired notation is not working as expected

#SpringBootApplication
public class MainApplication {
#Autowired
static BibliographyIndexer bi;
public static void main(String[] args) {
SpringApplication.run(MainApplication.class, args);
bi.reindex();
}
}
#Repository
public class BibliographyIndexer {
...
}
Whenever I access the properties of bi I get a NullPointerException. I know the #Autowired notation didn't work. But why?
Note: both classes are under the same package.
Additional question: Since I want to run a method upon the start of the spring application. Is this the best approach since #pepevalbe's answer already gave me the workaround I needed. Is there another way to run a method upon the start of the spring application?
Because you can't #Autorwire an static class. It doesn't get initialized so you get a NPE when trying to use it.
There are workarounds to wire a bean into a static class, but it is strongly discouraged.
EDIT:
If you need to execute code after initilization you could add an event listener:
#SpringBootApplication
public class MainApplication {
#Autowired
BibliographyIndexer bi;
public static void main(String[] args) {
SpringApplication.run(MainApplication.class, args);
}
#EventListener(ApplicationReadyEvent.class)
public void doAfterStartUp() {
bi.reindex();
}
}
There are several reasons #Autowired might not work.
When a new instance is created not by Spring but by for example manually calling a constructor, the instance of the class will not be registered in the Spring context and thus not available for dependency injection. Also when you use #Autowired in the class of which you created a new instance, the Spring context will not be known to it and thus most likely this will also fail.
Another reason can be that the class you want to use #Autowired in, is not picked up by the ComponentScan. This can basically be because of two reasons.
The package is outside the ComponentScan search path. Move the package to a scanned location or configure the ComponentScan to fix this.
The class in which you want to use #Autowired does not have a Spring annotation. Add one of the following annotatons to the class: #Component, #Repository, #Service, #Controller, #Configuration. They have different behaviors so choose carefully........
Your problem is that you cannot use bi in main because main is static.
Making bi static doesn't help because static fields will not be #Autowired (It is possible but does not make sense in the concepts of Dependency Injection).
Remove static and move bi.reindex() to a new method annotated with #PostConstruct. It will be executed after the MainApplication-bean is fully initialized and here you can use your injected bi.
In main method you can refer to context and from it get access to bean BibliographyIndexer. In static main spring can not creates and injects bean so this is how you can get it from context.
public static void main(String[] args) {
ApplicationContext context = SpringApplication.run(MainApplication.class, args);
BibliographyIndexer bibliographyIndexer = context.getBean(BibliographyIndexer.class);
bibliographyIndexer.reindex();
}
You can also do as in answer from pepevalbe and execute this code after initialization.

Spring boot #Inject proxy resolves to null

I'm refactoring an existing application to use Spring Boot. The issues I've faced here are generally of the type "why is this not working anymore".
I have three packages
- nl.myproject.boot
- nl.myproject
- nl.myproject.rest
My current problem is that all #Services that I #Inject in a #RESTController resolve to null when a method is called on them.
The service and dao are part of the nl.myproject package and the reason it's not nl.myproject.core is a legacy issue.
A related issue is that my #Configuration components don't seem to be loaded through #ComponentScan and I have to import them manually. I also had to exclude Test configuration to prevent Test configs from being loaded, which also seemed weird.
Internal calls from the service layer during start up, such as data preparation works normally. Any such manager is also #Injected. This is just to say that any of the typical injection mistakes such as manual instantiation or injecting a class instead of an interface don't apply.
I'd also be grateful for debugging tips. My Java has gotten a little rusty.
#EnableAutoConfiguration
#ComponentScan(basePackages= {
"nl.myproject",
"nl.myproject.boot",
"nl.myproject.dao",
"nl.myproject.service",
"nl.myproject.webapp"},
excludeFilters= {
#ComponentScan.Filter(type=FilterType.REGEX,pattern={".*Test.*"}),
#ComponentScan.Filter(type=FilterType.REGEX,pattern={".*AppConfig"})
}
)
#Configuration
#EnableConfigurationProperties
#Import({
JPAConfig.class,
RestConfig.class,
BootConfig.class
})
public class Startup {
public static void main(String[] args) throws Exception {
SpringApplication.run(Startup.class, args);
}
}
#RestController
#RequestMapping(value="/json/tags")
public class JsonTagController extends JsonBaseController {
#Inject
TagManager tagMgr;
public interface TagManager extends BaseManager<Tag,Long> {
[...]
}
#Service("tagManager")
public class TagManagerImpl extends BaseManagerImpl<Tag, Long> implements
TagManager {
#Inject
TagDao dao;
[...]
#Inject is a annotation specified by JSR-330 (standard) whereas #Autowired is annotation specified by Spring.
They just do the same dependency injection. You can both of them in the same code.
Just the modification (separation of the concerns) you need :
public interface TagManager {
[...]
}
#Service
public class TagManagerImpl implements TagManager {
#Inject
private TagDao dao;
// inject that service rather than extending
#Inject
private BaseManager<Tag,Long> baseManager;
}
public interface BaseManager<Tag,Long> {
[...]
}
#Service
public class BaseManagerImpl<Tag,Long> implements BaseManager<Tag,Long> {
....
}
Just one thing you do for checking, just modify to basePackages= {"nl.myproject"} - just provide only base package, that's enough for spring to scan the components in every package.
Hope this may help :)

How to intercept a single method using SpringBoot AOP

I'm trying to output a log message whenever the function someFunction() gets invoked.
This is my Aspect:
#Aspect
#Component
public class MyAspect {
private static final Logger LOGGER = Logger.getLogger(MyAspect.class.getName());
#Pointcut("execution(com.practice.AOP.someFunction())")
public void outputLogMessage() {
LOGGER.info("someFunction has been invoked");
}
}
The method i'm trying to intercept, someFunction(), is in the com.practice.AOP class. When I invoke it (shown below), my Advice (the log message) doesn't output, nor do I get an error. What am I doing wrong? Is Pointcut even the way to go?
#SpringBootApplication
public class AOP {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
someFunction();
}
public static void someFunction() {
//should invoke the log message
}
}
Spring AOP only works on Spring beans, and only on public instance methods of those spring beans invoked from the outside (i.e. this.publicMethod() style invocations will not work, as they are not going through the proxies that Spring AOP creates to advise your spring beans.
If that is not enough for you, for instance if you need to advise not just spring beans but non-spring managed code as well, or static methods like in your example, you will need to switch to native AspectJ support, either by compile time weaving, or by load time weaving.

Execute CommandLineRunner outside #SpringBootApplication

This is based on https://spring.io/guides/gs/accessing-data-jpa/
I tried to move demo() in a different class in a different package (Application still on top of the filesystem hierarchy)
How do I make demo() run when i boot the project?
Application.java
package com.company.app
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class);
}
}
CommandLineRunner.java
package com.company.app.runner
public class Test {
#Bean
public CommandLineRunner demo() {
System.out.print("Run 1");
return (args) -> {
System.out.print("Run 2");
};
}
}
Add #Configuration to the Test class so that it is picked up when the classpath is scanned.
I haven't seen a Lambda for the CommandLineRunner before. Very nifty and saves having to create a class that specifically implements the CommandLineRunner.
Otherwise, you could implement CommandLineRunner to test and annotate as #Component.
#Component
public class ApplicationLoader implements CommandLineRunner {
#Override
public void run(String... strings) throws Exception {
System.out.print("Run 2");
}
}
* Update *
Answering the question in the comment with this update as I have more room to type...
#SpringBootApplication composes those other annotations as you indicated but those annotations are only applied to the specific class that it is defined on. The #Configuration annotation is telling Spring that the class defines beans that should be managed by the application context. The #ComponentScan tells spring to look through the classpath for classes that have specific annotations (e.g. #Component, #Service, #Configuration) and then act on those classes based on the type of annotation. the #EnableAutoConfiguration is the magic that loads appropriate beans based on the project dependencies (e.g. if mongo driver is on the classpath then create a MongoTemplate).

getting #autowired intance null when try trying to do operation on it,throwing null pointer exception

I am trying to save data on gemfire using crud repository. I have created one operation class to call save method of repository but at autowired instance I am getting null pointer exception. Below is my code:
public interface GeodeRepository extends CrudRepository<KeyValueBean, String> {
#Override
public KeyValueBean findOne(String name);
#Override
public <S extends KeyValueBean> Iterable<S> save(Iterable<S> entities);
}
#EnableGemfireRepositories(basePackageClasses = GeodeRepository.class)
#EnableAutoConfiguration
#Configuration
public class Operations {
#Autowired
private GeodeRepository repository;
public void saveKeyValueData(KeyValueBean keyValueBean) {
System.out.println("Repository is : " + repository);
repository.save(Arrays.asList(keyValueBean)); // <--- i am getting
// repository as null so
// getting null pointer
// exception
}
}
When we #Autowired any class make sure, you have declared that class as a #Component.
for example:
#Component
public class Operations {
#Autowired
private GeodeRepository repository;
public void saveKeyValueData(KeyValueBean keyValueBean) {
System.out.println("Repository is : " + repository);
repository.save(Arrays.asList(keyValueBean));
}
}
and try using #Autowired to Operation class to your class
in which class your are calling your saveKeyValueData() method.
So, what is not apparent from your example is how you "bootstrap" your application and it's features (e.g. Repositories) into action.
It is not simply enough to add the Spring #Configuration, Spring Boot's #EnableAutoConfiguration and SD GemFire's #EnableGemfireRepositories annotations and expect everything to be auto-configured and wired up successfully. I.e. you need a bootstrapping mechanism, like Spring Boot, especially if you are using the #EnableAutoConfiguration annotation.
For example...
import org.springframework.boot.SpringApplication;
...
class MyApplication {
public static void main(String[] args) {
SpringApplication.run(Operations.class, args);
}
}
Now, you could remove the #EnableAutoConfiguration from your Operations class and add the #SpringBootApplication to the MyApplication class, like so...
#SpringBootApplication
class MyApplication {
...
}
#SpringBootAppliation combines together Spring's #Configuration with Spring Boot's #EnableAutoConfiguration, along with many other useful meta-annotations, like Spring's #ComponentScan, enabling all sorts of magic to happen.
But, if you are not using Spring Boot, you can always bootstrap you application with the AnnotationConfigApplicationContext, like so..
class MyApplication
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext =
new AnnotationConfigApplicationContext(Operations.class);
applicationContext.registerShutdownHook();
}
}
This is essentially what the Spring Boot, SpringApplication class does for you anyway.
If you are developing a Web application, then of course you can specify the type of ApplicationContext created since you are using Java config, for instance. See here for more details.
Hope this helps!
Cheers,
John

Resources