What would be a somewhat equivalent class for TransactionScope(.Net) in Spring.
I know absolutely nothing about .Net, so I'm not certain if this is what you're looking for. You can use SimpleTransactionScope in order to maintain objects across the lifecycle of a transaction. It is not registered by default, so you will have to register it with spring core like any custom scope, and give it a stringy name. Then if you want you can also create an annotation specifically to register one.
It was my issue that suggested this a few years ago, after this question was created for certain. We requested it specifically for timestamps across multiple methods for injection in a service. You can do something like this.
public class SimpleTransactionFactoryPostProcessor implements BeanFactoryPostProcessor {
#Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory factory) throws BeansException {
factory.registerScope("transaction", new SimpleTransactionScope());
}
}
#Configuration
class MyConfiguration {
#Scope(scopeName = "transaction")
#Bean
Instant nowInstant() {
return Instant.now();
}
}
#Service
class MyService {
private final ObjectFactory<Instant> nowFactory;
MyService( #Qualifier("nowInstant") ObjectFactory<Instant> nowFactory ) {
this.nowFactory = nowfactory
}
#Transactional
public boolean nowisEqualAlways() {
var now = nowFactory.getObject();
var sameNow = nowFactory.getObject();
return Objects.equals( now, sameNow );
}
}
If you don't do this, your now could actually change during your transaction by a small amount of time. You can test that simply by spamming now calls in a test.
It may not be required for your needs, so it's hard for me to tell (obviously your needs are probably long past, hopeful.y this helps someone in the future though)
The #Transactional annotation looks equivalent.
This can be placed on classes and methods and can be defined with propagation, isolation, rollback etc.
Related
The problem:
The problem appears in a k8s pod running spring-boot, java 8 (more details below)
When using ObjectProvider<> and calling *provider.getObject(.....)*, on
a prototype bean defined in Spring Configuration, every now and then (never
find a way to make it happen regularly) setter injection methods are not called.
Update oct, 2: See Spring Issue #25840
Most of the time this works perfectly well, but sometimes, it constructs a new object
but misses to call the #Autowired setter method (checked with log information).
We also discover that 90% of the time it happens after application startup, but not always.
UPDATE sept, 21: Deleting (Restarting) de pod solves the problem.
UPDATE sept, 22: Once it happens it will happen all the time, I mean is not that it fails once, and the next time it works ok, it will always fail to call setters.
UPDATE sept, 23: New evidence related to concurrency problem in the real application, didn't appear until now, a single thread alone seemed
to generate the problem. (take a look at classes below to understand better
this description)
ToipParentClass (this is a Strategy Implementation) has setter #Autowired for
VlocityService
OrderManagemenService
InternetParentClass (this is a Strategy Implementation) has setter #Autowired for
VlocityService
OrderManagemenService
Log (commented)
[-nio-80-exec-10] GuidTaskController : Build Strategy using XOM_TOIP_OFFER .
[p-nio-80-exec-2] GuidTaskController : Build Strategy using XOM_INTERNET_OFFER .
[-nio-80-exec-10] ToipParentClass : #Constructing ToipParentClass
[p-nio-80-exec-2] InternetParentClass : #Constructing InternetParentClass
[-nio-80-exec-10] ToipParentClass : #Autowiring VlocityServices#7951cd46
[p-nio-80-exec-2] InternetParentClass : #Autowiring VlocityServices#7951cd46
[-nio-80-exec-10] ToipParentClass : #Autowiring OrderManagementService#3385326a
-------------------------------------------------------------
ERROR !!! Missing #Autowiring log
[p-nio-80-exec-2] InternetParentClass : #Autowiring OrderManagementService#7951cd46
-------------------------------------------------------------
[p-nio-80-exec-2] Controller : Unexpected Error
2020-09-22T18:56:45.544525916Z
-------------------------------------------------------------
ERROR: NullPointer when using not set OrderManagementService
-------------------------------------------------------------
2020-09-22T18:56:45.544530395Z java.lang.NullPointerException: null
2020-09-22T18:56:45.544534074Z at InternetParentClass.generateIds(InternetParentClass.java:50) ~[classes!/:BUG001_PrototypeBeanAutowired-8]
2020-09-22T18:56:45.544538568Z at GuidTaskController.setGUID(GuidTaskController.java:180) ~[classes!/:BUG001_PrototypeBeanAutowired-8]
I made a simple test in https://github.com/toniocus/strategy-calculator run it standalone, different jdk8 versions, also in the same docker image used in the pod (all things in the project), and failed to make it FAIL.
Any ideas on where to look for a problem, suggestions on what to try, or even
a solution :-), will be greatly welcome, thanks in advance
Below the product versions, classes.
Detail about versions:
k8s:
v1.14.9-eks-658790
spring-boot:
2.1.4.RELEASE
JDK:
openjdk version "1.8.0_212"
OpenJDK Runtime Environment (IcedTea 3.12.0) (Alpine 8.212.04-r0)
OpenJDK 64-Bit Server VM (build 25.212-b04, mixed mode)
The Classes
A snippet on the classes involved, no real code, do not worry about syntax errors.
(real code can be found in https://github.com/toniocus/strategy-calculator)
// ============================================================
public interface Strategy {
void work(...);
}
// ============================================================
#Service
public class Service {
public void doSomething() {
......
......
}
}
// ============================================================
public class MobileStrategy implements Strategy {
private Service service;
#Autowired
public void setService(Service s) {
this.service = s; // setter not called every now and then
}
public void work(...) {
this.service.doSomething(); // throws NullPointerException every now an then
}
}
// ============================================================
public enum StrategyEnum {
MOBILE("mobileKey", MobileStrategy.class),
TV("tvKey", TvStrategy.class),
.......
public Class<Strategy> getImplementationClass() {
......
}
public StrategyEnum findByKey(String key) {
.....
}
}
// ============================================================
#Configuration
public class Configuration {
#Bean
#Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public Strategy getStrategy(final StrategyEnum selectorEnum) {
try {
Constructor<? extends Strategy> constructor =
selectorEnum.getImplementationClass().getConstructor();
return constructor.newInstance();
}
catch (Exception ex) {
throw new Exception("Not able to instantiate interface implementation"
+ " for enum: " + selectorEnum
, ex);
}
}
}
// ============================================================
#RestController
public class MathOperRestController {
#Autowired
ObjectProvider<Strategy> provider;
#GetMapping("/{operation}/{x}/{y}")
public BigDecimal add(
#PathVariable("operation") final String operation
, #PathVariable("x") final BigDecimal x
, #PathVariable("y") final BigDecimal y
) {
Strategy strategy = this.provider.getObject(StrategyEnum.findByKey(operation));
strategy.doWork(x, y);
return BigDecimal.ZERO;
}
UPDATE sept,21 added Service class to samples
The problem I found
Update oct, 1: Please read #Denium comment in the question !!!! (thanks for it).
After today's (Sept, 23) update, seems clearly the problem is a concurrency problem, I was able to reproduce it easily (See SimpleSpringAppTest.java)
in a Simple Spring app, no spring-boot.
Made all Strategy implementations have the same set of #Autowired setters
and the error is still there.
Seems there is some caching done, and #Autowired setters are taken from the cache, and not from the newly constructed object, although I try to dig into spring sources difficult to understand in so short time.
The problem was solved, avoiding concurrency (changes below), so now my question:
Is this the expected behaviour or is it a bug ?
I was not able to find any documentation regarding this problem or describing this behaviour anywhere, so still a question for me.
I tested in spring-boot versions 1.5.22, 2.1.4 (what we are currently using), and 2.3.4 and in all cases the same problem appears, just in a simple spring application, no need of RestController or so.
Workaround 1
Add an intermediate Factory to ensure Strategy beans are created 'synchronously'.
Update oct, 1: After #Deinum comments, from what I understood, Spring will be scanning classes every time (or almost every time) for annotations, so I guess Workaround 2 is probably a better solution.
This solution is more suitable for my current environment.
New Class StrategyFactory
Note the getStrategy(...) method is synchronized, I guess this solution
will have some performance impact, but still not able to measure it.
#Component
public class StrategyFactory {
#Autowired
ObjectProvider<Strategy> provider;
public synchronized Strategy getStrategy(final MathOperEnum operation) {
return this.provider.getObject(operation);
}
}
Changes in RestController
Now using the StrategyFactory instead of the ObjectProvider
#RestController
public class MathOperRestController {
#Autowired
StrategyFactory factory;
#GetMapping("/{operation}/{x}/{y}")
public BigDecimal add(
#PathVariable("operation") final String operation
, #PathVariable("x") final BigDecimal x
, #PathVariable("y") final BigDecimal y
) {
Strategy strategy = this.factory
.getStrategy(StrategyEnum.findByKey(operation));
strategy.doWork(x, y);
return BigDecimal.ZERO;
}
}
Workaround 2
Make the StrategyFactory ApplicationContextAware
Add #Componente/#Scope annotation to each strategy implementation
Remove #Configuration class
#Component
public class StrategyFactory implements ApplicationContextAware {
private ApplicationContext ctx;
public Strategy getStrategy(final StrategyEnum operation) {
return this.ctx.getBean(
operation.getImplementationClass()
);
}
#Override
public void setApplicationContext(
final ApplicationContext applicationContext)
throws BeansException {
this.ctx = applicationContext;
}
}
This is not the correct way to create an instance of Strategy bean in Configuration#getStrategy method as it will not call setter using autowiring.
Constructor<? extends Strategy> constructor =
selectorEnum.getImplementationClass().getConstructor();
return constructor.newInstance();
The way #Autowired is used, it seems you want to create a bean of which instance creation is handled by Spring.
You can refer this answer https://stackoverflow.com/a/52355649/2614885 to use AutowireCapableBeanFactory which creates bean in spring container for the bean id you specify which seems to be either 'mobileKey' or 'tvKey' in your case.
try following code in your #Configuration class
#Configuration
public class Configuration {
#Autowired private AutowireCapableBeanFactory autowireCapableBeanFactory;
#Bean
#Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public Strategy getStrategy(final StrategyEnum selectorEnum) {
try {
Constructor<? extends Strategy> constructor =
selectorEnum.getImplementationClass().getConstructor();
Strategy strategyBean = constructor.newInstance();
autowireCapableBeanFactory.autowireBean(strategyBean);
return strategyBean;
}
catch (Exception ex) {
throw new Exception("Not able to instantiate interface implementation"
+ " for enum: " + selectorEnum
, ex);
}
}
}
I'm developing a translation service that currently works inside another Service. For example:
public Profile getById(int chainId, int profileId, Integer languageId) {
Profile profile = profileRepository.getById(chainId, profileId);
translationService.translate(profile, languageId); // Here
return profile;
}
Now, to avoid to use a translate method on every service method of all the application, and as I only have the language of a user from the controller, I would like to execute the translate method before every Profile (and any other object) is returned to the client.
I tried to implement HandlerInterceptor in a custom interceptor, but it seems it doesn't returns the instance of the object that I'm returning. Anyone could help?
Another way to do it could be to translate every object that came from a select in Hibernate, but I also don't find any good solution to it this way...
The solution was to use Spring AOP. Probably the question wasn't very well explained, but what we needed was a way to intercept the object a user was asking to the backend, because they are able to create their own translations and we save them in the database. We had to return the model with the correct translation for each user, who has their localization in their profile. Here's the way we intercept it:
#Component
#Aspect
public class TranslatorInterceptor extends AccessApiController {
Logger logger = LoggerFactory.getLogger(this.getClass());
#Autowired
public TranslationService translationService;
#Pointcut("execution(* com.company.project.api.controller.*.get*(..))")
public void petitionsStartWithGet() { }
#Pointcut("execution(* com.company.project.api.controller.*.list*(..))")
public void petitionsStartWithList() { }
#Pointcut("execution(* com.company.project.api.controller.*.find*(..))")
public void petitionsStartWithFind() { }
#AfterReturning(pointcut = "petitionsStartWithGet() || petitionsStartWithList() || petitionsStartWithFind()", returning = "result")
public void getNameAdvice(JoinPoint joinPoint, Object result){
translationService.translate(result, getCustomUserDetails().getLanguageId());
logger.debug("Translating " + result.getClass().toString());
}
}
What we do here is to "watch" all the methods in the package "controller" that start by 'get', 'list' or 'find' (getById(), for example) and through this advice, we intercept the object before is sent to Jackson. The method getCustomUserDetails comes from AccessApiController, which is a class we did to provide our Controllers with some information we need.
Is it bad practice to use dependency injection in factory classes? Should I let the users of my framework take care of dependency injection? Should I use approach A or approach B?
SomeUserClass
package com.impl;
#Service
public class SomeUserClass {
#Autowired
private SMSActionFactoryService actionFactoryService:
#Autowired
private PropertyManager properties;
public void doStuff(){
// approach A
SMSAction action = actionFactoryService.createAction("hello");
// approach B
action = SMSActionFactory.createAction(properties, "hello");
// the user should never call Action::doAction.
// It gets called by the framework on a condition.
scheduler.addAction(State.ERROR, action)
}
}
SMSAction
package com.framework;
public class SMSAction extends Action {
public SMSAction(PropertyManager properties, String message){
}
public void doAction(){
}
}
SMSActionFactoryService
package com.framework;
#Service
public class SMSActionFactoryService {
#Autowired
private PropertyManager properties;
public SMSActionFactory createAction(String message) {
return new SMSActionFactoryService(properties, message);
}
}
SMSActionFactory
package com.framework;
public class SMSActionFactory {
public static SMSActionFactory createAction(PropertyManager properties, String message) {
return new SMSActionFactory(properties, message);
}
}
I think you have a context problem, so the answer depends on the context. But I'll give some of my experience, and not a formal (and irrefutable) answer. Based on the title of the answer (practices) I'll give you what I call good practices tips that helped me a lot when I started Spring development.
First of all, let's think about the Dependency Injection you have. You're wiring a field, and we know that the Spring team used to suggest us to use constructor based injection (and assertions for all mandatory dependency) as you can see here. Well, I know it was a problem with the tests framework that couldn't wire the dependencies in an easy way, but now they can. But there's another advantage using this pattern, you can make your bean field final. Another advantage is that you prevent circular dependencies, like X depends on Y and Y depends on X and so on. So, as the first tip, I would suggest you to use something like:
private final SMSActionFactoryService actionFactoryService:
private final PropertyManager properties;
#Autowired
public SomeUserClass(SMSActionFactoryService actionFactoryService,
PropertyManager properties) {
Assert.notNull(actionFactoryService, "The actionFactoryService bean is null, you should provide the bean to run this application");
Assert.notNull(properties, "The properties bean is null, you should provide the bean to run this application");
this.actionFactoryService = actionFactoryService;
this.properties = properties;
}
This way you prevent any other code part to change the field value. As you can see in Spring autowiring setter/constructor PROs and CONs this is a preference subject.
Now, for the second tip, I wouldn't use #Service for a factory, not even #Component because factories needs to be open for extension and close for modification. You're going to understand better if take a look here.
That said friend, I suggest you to embrace approach B.
In my Spring application, I have components that use Spring's caching mechanism. Each #Cacheable annotation specifies the cache that is to be used. I'd like to autodiscover all the caches that are needed at startup so that they can be automatically configured.
The simplest approach seemed to create a marker interface (ex: CacheUser) to be used by each caching component:
#Component
public class ComponentA implements CacheUser {
#Cacheable("dictionaryCache")
public String getDefinition(String word) {
...
}
}
I would then have Spring autodiscover all the implementations of this interface and autowire them to a configuration list that can be used when configuring the cache manager(s). This works.
#Autowired
private Optional<List<CacheUser>> cacheUsers;
My plan was to take each discovered class and find all methods annotated with #Cacheable. From there I would access the annotation's properties and obtain the cache name. I'm using AnnotationUtils.findAnnotation() to get the annotation declaration.
That's where the plan falls apart. Spring actually wires proxies instead of the raw component, and the annotations aren't copied over to the proxies' methods. The only workaround I've found exploits the fact that the proxy implements Advised which provides access to the proxied class:
((Advised)proxy).getTargetSource().getTargetClass().getMethods()
From there I can get the original annotations, but this approach is clearly brittle.
So two questions, really:
Is there a better way to get to the annotations defined by the proxied class?
Can you suggest any other way to discover all uses of #Cacheable in my project? I'd love to do without a marker interface.
Thanks!
Spring has a lot of infrastructure interfaces which can help you tap into the lifecycle of the container and/or beans. For your purpose you want to use a BeanPostProcessor and the SmartInitializingSingleton.
The BeanPostProcessor will get a callback for all the beans constructed, you will only need to implement the the postProcessAfterInitialization method. You can in that method detect the annotations and fill a list of caches.
Then in the SmartInitializingSingletons afterSingletonsInstantiated method you use this list to bootstrap/init your caches.
Something like the following (it is untested but should give you an idea).
public class CacheInitialingProcessor implements BeanPostProcessor, SmartInitializingSingleton {
private final Set<String> caches = new HashSet<String>();
#Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
#Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
Class<?> targetClass = AopUtils.getTargetClass(bean);
ReflectionUtils.doWithMethods(targetClass, new ReflectionUtils.MethodCallback() {
#Override
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
Cacheable cacheable = AnnotationUtils.getAnnotation(method, Cacheable.class);
if (cacheable != null) {
caches.addAll(Arrays.asList(cacheable.cacheNames()));
}
}
});
return bean;
}
#Override
public void afterSingletonsInstantiated() {
for (String cache : caches) {
// inti caches.
}
}
}
Hopefully my question is fairly self-explanatory - I will illustrate it with some example code.
#Component
#PropertySource("classpath:/my-properties.properties")
public class SomeProperties {
#Autowired
Environment env;
// private methods
public boolean isEnabled(Foo foo) {
// call private methods, call env.getProperty, return value
}
}
#Component // it makes no difference whether it's there or not
public class MyCondition implements Condition {
#Autowired // doesn't make a difference
private SomeProperties someProperties;
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
// ...
boolean b = someProperties.isEnabled(foo); // get NPE on this line
// ...return
}
}
#Component
#Conditional(MyCondition.class)
public class Bar {
// stuff
}
(Here I'm using Spring Boot to configure Spring. Although I doubt it makes any difference - as #Component beans are definitely accessible post-bootstrap, so it doesn't seem to be a problem in the way Spring is configured.)
The problem is that I'm getting a NullPointerException on the indicated line, because someProperties is null. This is presumably because at the time that the condition is run, the autowiring/instantiation phase of Spring bootstrap has not happened yet.
Is there any way to access Spring Properties in this way - like force Spring to load a bean before it normally would? Or is the only way to use standard Java / Apache Commons properties code as opposed to Spring?