I don't know if it is the better way to implement my solution:
#Component
#Scope("singleton")
public class GetFromJson implements Serializable{
/**
*
*/
private static final long serialVersionUID = -8203722696439228358L;
Map<String, Map<String, ArrayList<String>>> jsonMap;
public Map<String, Map<String, ArrayList<String>>> getJsonMap() {
return jsonMap;
}
public void setJsonMap(Map<String, Map<String, ArrayList<String>>> jsonMap) {
this.jsonMap= jsonMap;
}
}
The class is Serializable because I get the content from a Json from a database and I map the content in an Object GetFromJson (I need do the query in database only one time). For this reason I need use the Object in all my APp, for this reason I think that I need use a Singleton
Somebody publish to me a library to get the JSON from database. the JSON object parse to Map<String, Map<String, ArrayList<String>>> for this reason I create my GetFromJson class.
Now I have many rest Service, in my rest services I need use my object: GetFromJson to get the content of jsonMap.
I have many questions.
With the annotation #Scope("singleton") I guarantee have the GetFromJson only one instance available in all my app?
Or what is the better way to have in Spring a singleton and session object available in my app?
To access to get the content of jsonMap of GetFromJson is enough use
#Autowired
private GetFromJson jsonObject;
Or how can I get my singleton class?
and in my rest method service use:
jsonObject.getJsonMap();
How can Initialize my singleton, because i am trying initialize my object with:
#Autowired
private GetFromJson jsonObject;
public methodToInitialize(){
jsonObject = methodLibraryFromDatabase(GetFromJson.class);
}
ANd the IDE tell to me that the field initialization is not used
I need the same logic, but with session Object, I think that if I understand the singleton implementation with my session object will be the same but only changing the anotation to: #Scope("session")
I think what OP is wants to initialize database based POJO once in application lifecycle and autowire it where needed.
Typically this is done by creating a bean (which are singletons unless otherwise specified) and autowiring it where needed.
This sample should get you started.
#Configuration // beans are declerated in #Configuration classes
public class GetJsonInitializer {
#Bean // singleton by default
public GetFromJson jsonMap(){
GetFromJson jsonObject = methodLibraryDatabase(GetFromJson.class);
return jsonOBject;
}
}
Now autowire GetFromJson in any Spring service/component etc.
#Service
public class SomeService {
#Autowired
private GetFromJson jsonMap;
}
Hope this helps!
a bean annotated with session scope is going to be bound to user's session life cycle, that is, for each user accessing your app, you'll have an instance of this class. If you want to guarantee only one instance of this bean in your application (at JVM level) you just need to remove the #Scope annotation. However, if you want to mix singletons with session scoped beans, then you should just let spring handle everything seamless for you, your session scope beans will only be destroyed when the user session ends.
The best way to handle initialization code in your bean is in a public method annotated with javax.annotation.PostConstruct
#PostConstruct
public void setUp() {
//initialization code
}
In order to handle a clean up code when a bean is going to be destroyed, you should make your class implement org.springframework.beans.factory.DisposableBean or add a method annotated with javax.annotation.PreDestroy
#PreDestroy
public void onDestroy() {
//clean up code
}
I hope this has helped you out!
Related
I am running into an issue with my Spring Applications and SonarQube. SQ is flagging both examples with "Annotate this member with "#Autowired", "#Resource", "#Inject", or "#Value", or remove it." on the instance variable mapLoadedByDatabaseCalls
Example 1:
#Service
public class Service implements InitializingBean {
#Autowired
private Dao dao;
private Map<Object, Object> mapLoadedByDatabaseCalls;
#Override
public void afterPropertiesSet() throws Exception {
mapLoadedByDatabaseCalls= new HashMap<>(Object.class);
....
}
}
Example 2:
#Service
public class Service {
#Autowired
private Dao dao;
private Map<Object, Object> mapLoadedByDatabaseCalls;
#PostConstruct
private void setMap() {
mapLoadedByDatabaseCalls= new HashMap<>(Object.class);
....
}
}
What is the correct way to instantiate variables after DI has completed?
A more generic solution to this that does not involve any additional annotations, is to initialize the offending variable in the class constructor.
public Service() {
mapLoadedByDatabaseCalls = new HashMap<>();
}
I believe that this is kludgy and that your original code is better, but this will eliminate the SonarQube complaint. Initialize your map in a #Bean, then reference that as #Autowired. Load the map with data in the #PostConstruct.
#Bean
public Map<Object, Object> getMapLoadedByDatabaseCalls() {
return new HashMap<>(Object.class);
}
#Autowired
private Map<Object, Object> mapLoadedByDatabaseCalls;
#PostConstruct
private void setMap() {
...
// load data into the map
mapLoadedByDatabaseCalls.put(key, value);
....
}
From the Spring Documentation > Initialization callbacks section
It is recommended that you do not use the InitializingBean interface
because it unnecessarily couples the code to Spring. Alternatively,
use the #PostConstruct annotation or specify a POJO initialization
method.
Essentially InitializingBean pre-existed in Spring before the JSR-250 support came on Spring 2.5 onwards (including the #PostConstruct annotation)
The rule S3749 describes that Spring #Component, #Controller, #Service, and #Repository classes are singletons by default, meaning only one instance of the class is ever instantiated in the application. Typically such a class might have a few static members, such as a logger, but all non-static members should be managed by Spring. That is, they should have one of these annotations: #Resource, #Inject, #Autowired or #Value.
Having non-injected members in one of these classes could indicate an attempt to manage state. Because they are singletons, such an attempt is almost guaranteed to eventually expose data from User1's session to User2.
Given the above details, Spring should be managing its all non-static members states. It all depends on the use case and should be avoided either using #Autoworied, class constructor or #PostConstruct.
SECURITY WARNING: OWASP A3:2017. This could leak sensitive data
I am just wondering what a good architecture design looks like.
Let's say we have a CarRepository which manages all beans of type Car in a car rental application.
Car beans are of type prototype
CarRepository bean is of type repository (singleton)
Now, the CarRepository is asked to create a new Car bean, e.g. when the rental company has bought a new car.
Of course, I could implement ApplicatioContextAware and use context.getBean("car"), but for me, it doesn't fit well to the idea of dependency injection. What is best-practice for injecting a shorter-lived bean into a singleton?
Update: Maybe I should add an example to make it more clear.
#Repository
public class CarRepository {
private List<Car> cars;
public void registerNewCar(int id, String model) {
// I don't want to access the Spring context via ApplicationContextAware here
// Car tmp = (Car) context.getBean("car");
// car.setId(id);
// car.setModel(model);
// cars.add(tmp);
}
}
#Scope("prototype")
public class Car {
private int id;
private String model;
// getter and setters
}
Spring offers a mechanism that handles injecting a shorter-lived bean in a longer-lived one. It's called a scoped proxy. How it works is that the singleton is injected with a proxy that will handle method calls by searching the shorter scope (like session or request) for a bean instance and delegating to that instance.
You didn't specify, if you are using xml or annotations to configure your application or what version of Spring you are using. You can read more about configuring the scope proxy with xml in the reference guide. I'm going to give you an example how to configure it with annotations in a Spring 4-ish environment.
For me the best way is to use the meta-annotations mechanism. It allows you to create your own annotations that will be later used by Spring to configure your app. For example:
#Retention(RUNTIME)
#Scope(value=WebApplicationContext.SCOPE_SESSION, proxyMode=ScopedProxyMode.TARGET_CLASS)
public #interface SessionScoped{
}
Such an annotation, when specified on a #Component (or #Service or any other specialization) class or a #Bean method in your Java config will cause that bean to be injected as a proxy. For example:
#Configuration
#EnableAspectJAutoProxy
public class MyConfig{
#SessionScoped
#Bean
public MyClass myBean(){
// return your bean
}
}
All that being said, your example really makes me think you should be working with entities (Car) and repositories. See Spring Data if you are designing the model layer and you want to store Cars data in your database etc.
If you do not want to use context.getBean(...), then, you can construct the car using new Car(...) as it will have same effect.
These are only two ways!
I have a class that has some dynamic attributes which I received on the constructor.
Other properties on this same class are/can be injected by spring.
I want to know if this is possible and how should I config my application. I using spring 3 and xml configuration.
Here is an example:
class MyClass {
private MyClass2 obj2; // should be injected by spring
private Long myId;
public MyClass(Long dynamicId) {
myId = dynamicId;
}
public void doSomehting() {
obj2.doOtherStuff(this);
}
}
So, what I want, since I must create MyClass dynamically, is that after I call new MyClass(1234), the obj2 gets injected by Spring.
Is it possible?
use an ObjectFactory to retrieve the bean from the di-container. If you wrap this factory in a factory object of your own, you can set any property and still have the bean managed by Spring. Since you want the bean to have some dynamically set property think it through whether you need a singleton-scoped bean (default) or a prototype one.
If you intend to do this from xml config you need to muck around with objectfactorycreatingfactorybean. Spring documentation is excellent, just follow the example.
If you do annotation-based configuration, you just need to autowire the ObjectFactory. Note that YourClass has to be declared as a bean too!
I'm pretty sure that's not possible. It looks like you want a (scary music) factory.
class MyClassFactory {
private final MyClass2 object;
public(MyClass2 object) {
this.object = object;
}
public createMyClass(Lond id) {
return new MyClass(id, object);
}
}
If you create an instance of MyClass dynamically with the new operator, that instance is outside of Spring's bean factory, so Spring cannot inject anything. You really have two options, from what I can see.
1) Make MyClass a prototype bean so Spring gives you a new instance every time you need it. You would need to then define obj2 as a property to be set (or Autowired).
2) Inject obj2 via Spring into the class that is creating the instance of MyClass and make obj2 a constructor argument so you have to inject it.
My 0.02 from what I read from your question. A note of caution, when creating a new instance in Java, it is always outside the bean factory and all work performed outside the bean factory looses the Spring proxy behaviors. Be very careful here, you can get yourself into a rabbit hole that can be hard to track down.
Say I have the following class...
#Controller
public class WebController {
#Autowired PersonService personService;
#RequestMapping(value = "/get", method = RequestMethod.GET)
#ResponseBody
#Scope("session")
public List<Player> getPerson(String personName) {
return playerService.getByName(personName);
}
}
Now this invokes the following service...
#Service("playerService")
public class PlayerServiceImpl implements PlayerService {
private List<Player> players;
#Override
#Transactional
public List<Player> getByName(final String name) {
if (players == null) {
players = getAll();
}
return getValidPlayers(name);
}
If I initially start my application, players is null, correctly, then when in the same session, I invoke this method again with a new value, players is no longer null, as you would expect. However, no new thread appears to be being created, if I open a new browser window (therefore creating a new session) and invoke this method, it still has the values from the previous session.
Why is #Scope("session") not creating a new thread in the thread pool?
I've specified <context:component-scan base-package="com." /> in my servlet-context as expected, everything works fine apart from the service methods are all acting as singletons rather than creating a new thread per session like say a Java EE container.
If players was marked as static I'd understand.
I've also tried marking my controller as #Scope("session") (as shown below) but this appears to have no impact either. What's the best way to make my Spring app create a new thread for a new session?
#Controller
#Scope("session")
public class PlayerController {
You are using #Scope annotation the wrong way.
Quoting the docs:
When used as a type-level annotation in conjunction with the Component annotation, indicates the name of a scope to use for instances of the annotated type.
When used as a method-level annotation in conjunction with the Bean annotation, indicates the name of a scope to use for the instance returned from the method.
So you can annotate either a spring component bean or a method that creates a bean if you're using java config. Java config is the only reason it even compiles (it wouldn't in pre 3.0 spring)
In your case that annotation is on a normal bean method where it doesn't mean anything.
Solving the right problem
It looks like you're trying to implement db cache by storing query results in a List<Player> players.
Don't do that. Use one of the prebuilt cache abstractions (spring has a very nice one) instead.
So where should #Scope go?
Annotating #Controller with #Scope("session") won't help as it will create session scoped controllers but the service they have injected is still a singleton.
Annotating only Service bean won't work either, cause #Controller is a singleton and it's dependencies are autowired on application startup.
Annotating both #Service and #Controller might work, but seems a bit heavy handed.
It's better to avoid state at all.
New threads are created for each request.
Your service has an instance variable (players) which is not threadsafe - it is shared by all threads. Any spring bean - including controllers and services are by default a singleton, you need to specify on the service annotation its scope.
#Service("playerService")
#Scope("session")
public class PlayerServiceImpl
But its best(simpler, easier to scale) to keep beans singletons and not rely on instance variables (unless they are also managed by spring/threadsafe/singletons).
Is it possible to use #Configurable on a class that's weaved using AspectJ and get Spring to load in values on fields/methods which are annotated with #Value?
I know its possible with #Autowired and #Resource etc... Are there any others.
e.g.
#Configurable
public Class MyObj{
#Value("$(my.prop)")
private String aField;
public String getAField(){
return aField;
}
}
And then have something like
public aMethodSomewhereElse(){
MyObj obj = new MyObj()
assertNotNull(obj.getAField());
}
Are there any alternatives to being able to create MyObj with the new operator and still get spring to handle the annotations?
--EDIT:--
It IS possible to do this using new when using #Autowired, have a look at some Hibernate and JPA stuff with Spring and AOP... I've used this in the past to do some profiling of Java code. But I really want to use SPEL and #Value before I mock up a full example I was hoping to find the answer here. FYI - if you don't belive me the Spring Manual even says it is possible to do this, what I want to know is if its possible to use #Value annotations in the same scope...
The Spring container instantiates and configures beans defined in your
application context. It is also possible to ask a bean factory to
configure a pre-existing object given the name of a bean definition
containing the configuration to be applied. The spring-aspects.jar
contains an annotation-driven aspect that exploits this capability to
allow dependency injection of any object.
And...
Using the annotation on its own does nothing of course. It is the
AnnotationBeanConfigurerAspect in spring-aspects.jar that acts on the
presence of the annotation. In essence the aspect says "after
returning from the initialization of a new object of a type annotated
with #Configurable, configure the newly created object using Spring in
accordance with the properties of the annotation". In this context,
initialization refers to newly instantiated objects (e.g., objects
instantiated with the 'new' operator) as well as to Serializable
objects that are undergoing deserialization (e.g., via readResolve()).
http://static.springsource.org/spring/docs/3.0.0.RC2/reference/html/ch07s08.html
Cheers.
You are absolutely right - #Autowired fields will be wired in an #Configurable annotated class even outside of a Spring container, assuming that you have a AspectJ infrastructure in place.
You have noted a good catch though, #Value fields are processed by a Spring bean post processor(AutowiredAnnotationBeanPostProcessor), which resolves the #Value annotated fields. It does not act on objects instantiated outside of the container though - so in short, the #Autowired fields should get wired in, but #Value properties will not.
Doing
MyObj obj = new MyObj()
means that obj is not managed by spring, so it will not do autowiring.
Only way to do that is to obtain instance from an application context. For example:
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
MyObj obj = context.getBean("myBean");
I don't think it is possible to use new operator and ask spring to autowire properties. I think 1 way to solve this is to get a static reference to applicationContext and create a prototype scoped bean.
#Component
public class ApplicationContextLocator {
private static ApplicationContext applicationContext;
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
public ApplicationContextLocator() {
super();
}
#Autowired
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
ApplicationContextLocator.applicationContext = applicationContext;
}
}
#Scope(BeanDefinition.SCOPE_PROTOTYPE)
#Component
public class MyObj {
.....
}
public aMethodSomewhereElse(){
MyObj obj = ApplicationContextLocator.getApplicationContext().getBean(MyObj.class)
assertNotNull(obj.getAField());
}