I want to reinject singleton-scoped dependencies into prototype Spring beans, after they have been deserialized.
Say I've got a Process bean, which depends on a Repository bean. The Repository bean is a scoped as a singleton, but the Process bean is prototype-scoped. Periodically I serialize the Process, and then later deserialize it.
class Process {
private Repository repository;
// getters, setters, etc.
}
I don't want to serialize and deserialize the Repository. Nor do I want to put "transient" on the member variable that holds a reference to it in Process, nor a reference to some kind of proxy, or anything other than a plain old member variable declared as a Repository.
What I think I want is for the Process to have its dependency filled with a serializable proxy that points (with a transient reference) to the Repository, and, upon deserialization, can find the Repository again. How could I customize Spring to do that?
I figure I could use a proxy to hold the dependency references, much like . I wish I could use that exact technique. But the proxy I've seen Spring generate isn't serializable, and the docs say that if I use it with a singleton bean, I'll get an exception.
I could use a custom scope, perhaps, on the singleton beans, that would always supply a proxy when asked for a custom-scoped bean. Is that a good idea? Other ideas?
I used this instead, without any proxy:
public class Process implements HttpSessionActivationListener {
...
#Override
public void sessionDidActivate(HttpSessionEvent e) {
ServletContext sc = e.getSession().getServletContext();
WebApplicationContext newContext = WebApplicationContextUtils
.getRequiredWebApplicationContext(sc);
newContext.getAutowireCapableBeanFactory().configureBean(this, beanName);
}
}
The example is for a web environment when the application server serializes the session, but it should work for any ApplicationContext.
Spring provides a solution for this problem.
Take a look at the spring documentation http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/aop.html#aop-atconfigurable.
7.8.1 Using AspectJ to dependency inject domain objects with Spring
...
The support is intended to be used for objects created outside
of the control of any container. Domain objects often fall into
this category because they are often created programmatically
using the new operator, or by an ORM tool as a result of a database query.
The trick is to use load time weaving. Just start the jvm with -javaagent:path/to/org.springframework.instrument-{version}.jar. This agent will recognize every object that is instantiated and if it is annotated with #Configurable it will configure (inject #Autowired or #Resource dependencies) that object.
Just change the Process class to
#Configurable
class Process {
#Autowired
private transient Repository repository;
// getters, setters, etc.
}
Whenever you create a new instance
Process process = new Process();
spring will automatically inject the dependencies.
This also works if the Process object is deserialized.
How about added using aspects to add an injection step when you deserialize the object?
You would need AspectJ or similar for this. It would work very similarly to the #Configurable function in Spring.
e.g. add some advice around the a "private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException" method
This article may also help: http://java.sun.com/developer/technicalArticles/Programming/serialization/
I think the idea of serializing a bean and then forcing a reinjection of dependencies is not the best architecture.
How about having some sort of ProcessWrapper bean instead which could be a singleton. It would be injected with the Repository and either manages the deserialization of the Process or has a setter for it. When a new Process is set in the wrapper, it would call setRepository() on the Process. The beans that use the Process could either be set with the new one by the wrapper or call the ProcessWrapper which would delegate to the Process.
class ProcessWrapper {
private Repository repository;
private Process process;
// getters, setters, etc.
public void do() {
process.do();
}
public void setProcess(Process process) {
this.process = process;
this.process.setRepository(repository);
}
}
Answering my own question: how I've solved the problem so far is to create a base class which serializes and deserializes using a cheap little proxy. The proxy contains only the name of the bean.
You'll note that it uses a global to access the Spring context; a more elegant solution might store the context in a thread-local variable, something like that.
public abstract class CheaplySerializableBase
implements Serializable, BeanNameAware {
private String name;
private static class SerializationProxy implements Serializable {
private final String name;
public SerializationProxy(CheaplySerializableBase target) {
this.name = target.name;
}
Object readResolve() throws ObjectStreamException {
return ContextLoader.globalEvilSpringContext.getBean(name);
}
}
#Override
public void setBeanName(String name) {
this.name = name;
}
protected Object writeReplace() throws ObjectStreamException {
if (name != null) {
return new SerializationProxy(this);
}
return this;
}
}
The resulting serialized object is 150 bytes or so (if I remember correctly).
The method applicationContext.getAutowireCapableBeanFactory().autowireBean(detachedBean); can be used to reconfigure a Spring-managed bean that was serialized and then de-serialized (whose #Autowired fields become null). See example below. The serialization details are omitted for simplicity.
public class DefaultFooService implements FooService {
#Autowired
private ApplicationContext ctx;
#Override
public SerializableBean bar() {
SerializableBean detachedBean = performAction();
ctx.getAutowireCapableBeanFactory().autowireBean(detachedBean);
return detachedBean;
}
private SerializableBean performAction() {
SerializableBean outcome = ... // Obtains a deserialized instance, whose #Autowired fields are detached.
return outcome;
}
}
public class SerializableBean {
#Autowired
private transient BarService barService;
private int value;
public void doSomething() {
barService.doBar(value);
}
}
Related
I know similar questions have been asked so many times here before, but I am still confused by the mechanisms.
Here is my problem. There is a null pointer exception coming from the CategoryDAO object in the CategoryService.
#Service
public class CategoryService {
#Autowired
private CategoryDAO categoryDAO;
public List<Category> list(){
List<Category> categories = categoryDAO.list();
for (Category category : categories){
List<Record> rs = recordDAO.list(category.getID());
category.setRecordNumber(rs.size());
}
return categories;
}
public void add(String name){
Category newCategory = new Category();
newCategory.setName(name);
categoryDAO.add(newCategory);
}
}
#Repository
public class CategoryDAO {
#Autowired
private SqlSessionFactory sqlSessionFactory;
public int getTotal(){
SqlSession sqlSession = sqlSessionFactory.openSession();
List<Category> categories = sqlSession.selectList("category.selectAll");
return categories.size();
}
}
In this top rated post and this one, both of the top answers mentioned that The most preferable option is to let Spring autowire all of your beans.
Does it mean I have to also autowire the CategoryService in other classes once I need it? Which means I cannot use new operator to initialise a class if it contains autowired object?
If yes, could you please explain the reason behind it?
Thanks
UPDATE
Here is an example about using the autowired class CategoryService:
public class RecordListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
RecordPanel panel = RecordPanel.getInstance();
if (new CategoryService().list().size() == 0){
JOptionPane.showMessageDialog(panel, "NO category is recorded, set category first");
MainPanel.getInstance().getPanel().display(CategoryPanel.getInstance());
return;
}
}
The CategoryService is used in new CategoryService().list().size() == 0. If I autowire it as a property of this class here then this class will also need to be injected once I need it. I would like to avoid that so things could be easier. How can I achieve that?
Does it mean I have to also autowire the CategoryService in other classes once I need it?
Yes.
Which means I cannot use new operator to initialise a class if it contains autowired object?
Yes.
The #Autowire annotation enables you to use Dependency Injection. A technique (or good practice, actually) that makes it easy to change the implementations you use for your interfaces in your application. You define beans/component/services that will get injected whenever you use the #Autowire annotation over an attribute or a constructor parameter.
Instead of using new all over your code you just declare which concrete class should be used for an interface (or maybe the class itself) annotated with #Autowire.
Imagine you create an interface RemoteAccess and an implementation FtpRemoteAccess and then every time you need it you write RemoteAccess remoteAccess = new FtpRemoteAccess();
After a while you might end up with that line over several places. Now, if you need to change this to HttpRemoteAccess because you have this new, better alternative, you have to review all your code base. Instead, if you used dependency injection you would just change the bean (there is more than one way to do that using Spring).
For all this to work, Spring must be able to inject all the dependencies of a bean. If you create a bean, all its attributes must be injected too because Spring will create that object for you.
Clarification:
Inside your bean (namely, you classes that will be injected) you can create objects using new provided that makes sense and those object are not injected types. You are already doing that in CategoryService::add() and it is ok. Dependency injection doesn't mean you will not ever write new again. You will just avoid it for objects that will be managed by Spring dependency injection.
Then, there are other good practices that disencourage using new like the static factory method that recommend putting a static method in your class to build complete objects and letting the constructor to be private. But you don't need to apply all the patterns all the time.
UPDATE:
For your RecordListener class you have to add a CategoryService attribute and then be sure it is initialized. There are two options: you can convert RecordListener in a bean itself and have it autowired where you need that. This way Spring will construct a RecordListener object for injecting it and will also add any other bean that is needed (like CategoryService)
#Component
public class RecordListener implements ActionListener {
#Autowire
private CategoryService categoryService;
#Override
public void actionPerformed(ActionEvent e) {
RecordPanel panel = RecordPanel.getInstance();
if (categoryService.list().size() == 0) {
JOptionPane.showMessageDialog(panel, "NO category is recorded, set category first");
MainPanel.getInstance().getPanel().display(CategoryPanel.getInstance());
return;
}
}
}
The other option is you inject CategoryService in the class that is currently creating the RecordListener and then pass it as constructor argument. In that case RecordListener will not be a bean.
I have been refactoring a huge method in the project I work and came up with this idea to create a validation service like this -
public class TrickyValidation {
String validationVariable1;
String validationVariable2;
String validationVariable3;
HashMap<String, Object> itemsMap;
Object dependentObject;
#Autowired
SpringService service;
public static boolean doTrickyValidation(HashMap<String, Object> itemsMap, Object dependentObject) {
return new TrickyValidation(itemsMap, dependentObject).validate();
}
private TrickyValidation(Object itemsMap, Object dependentObject) {
this.itemsMap = itemsMap;
this.someDependentObject = dependentObject;
init();
}
private boolean validate() {
// loads of logic for validation by using validationVaribales
return true;
}
private void init() {
// Some methods to extract thease variables from itemsMap, dependentObject etc..
this.validationVariable1 = service.get(dependentObject);
this.validationVariable1 = ...;
this.validationVariable1 = ...;
}
}
My goal what I want to do here is to Encapsulate everything as much as possible and use clean code principles.
I feel a bit here like fighting spring framework because I don't want
that "TrickyValidation" class would be #Servcie and belong to spring container. Will Autowired even work here?
Is it a good design? Most likely I will use this validation in a loop. I like this solution because when I have to validate things I just simply call one and only public static method of this class TrickyValidation.doTrickyValidation(map, obj)
Any suggestions are welcome on how to improve this, or why it's a bad idea.
This code probably won't work because in the init method of the object you're trying to access service which is not autowired into this instance. In general the autowiring works only for objects managed (created by) Spring.
In this case you create "manually" the object of class TrickyValidation...
IMO the better design is to split the "Validator" object that can be Spring managed and the Validation itself that is not spring based.
#Component
public class Validator {
#Autowired
private Service service;
public boolean doTrickyValidation(HashMap<String, Object> itemsMap, Object dependentObject) {
// resolve the validation strategy from the items passed to this method.
TrickyValidation validation = resolveTrickyValidation(itemsPam, dependentObject);
return validation.validate();
}
private TrickyValidation resolveTrickyValidation(...) {
// construct the proper validation strategy
// access service if you want
}
}
I am migrating my current app in Spring/J2EE to Lagom. I am working in Java. I need to read variables from the configuration (application.conf in resources folder). In the implementation module, I try to inject configuration as a class variable like this
#Inject
private Configuration config
but when I access this config object in the constructor, it gives null pointer exception.
The whole code is like this
import play.Configuration;
public class SomeServiceImpl implements SomeService {
#Inject
private Configuration config;
public SomeServiceImpl() {
//getting configuration from application.conf
// gives exception as config is null.
String key = config.getString(“key”);
}
#Override
public ServiceCall<Request, Response> send() {
//works here, does not give exception
String key = config.getString(“key”);
}
}
Sorry, I should have been clear from the beginning. I have edited the original question. I get null pointer exception when I try to read from configuration object in constructor but I am able to use it in service call implementation. I want some way in which I can access the configuration in application.conf at startup and possibly store in some config class which can be accessed anywhere later.
In Java, when an object is instantiated, the first thing that happens (before anything else can possibly happen) is the constructor is invoked. After that, frameworks like Guice (which Lagom uses) are free to inject things, but they can't do it until the constructor has been invoked. So, all your #Inject annotated fields will be null when the constructor is invoked, there is nothing you can do to work around that.
So, don't use field injection, use constructor injection, eg:
import play.Configuration;
public class SomeServiceImpl implements SomeService {
private final Configuration config;
#Inject
public SomeServiceImpl(Configuration config) {
this.config = config;
String key = config.getString("key");
}
#Override
public ServiceCall<Request, Response> send() {
String key = config.getString("key");
}
}
Constructor injection is not just recommended for this use case, you should be using it everywhere, it avoids all these potential issues.
I am trying to define a custom DeltaSpike ConfigSource. The custom config source will have the highest priority and check the database for the config parameter.
I have a ConfigParameter entity, that simply has a key and a value.
#Entity
#Cacheable
public class ConfigParameter ... {
private String key;
private String value;
}
I have a #Dependent DAO that finds all config parameters.
What I am trying to do now, is define a custom ConfigSource, that is able to get the config parameter from the database. Therefore, I want to inject my DAO in the ConfigSource. So basically something like
#ApplicationScoped
public class DatabaseConfigSource implements ConfigSource {
#Inject
private ConfigParameterDao configParameterDao;
....
}
However, when registering the ConfigSource via META-INF/services/org.apache.deltaspike.core.spi.config.ConfigSource, the class will be instantiated and CDI will not work.
Is there any way to get CDI working in this case?
Thanks in advance, if you need any further information, please let me know.
The main problem is, that the ConfigSource gets instantiated very early on when the BeanManager is not available yet. Even the JNDI lookup does not work at that point in time. Thus, I need to delay the injection/lookup.
What I did now, is add a static boolean to my config source, that I set manually. We have a InitializerService that makes sure that the system is setup properly. At the end of the initialization process, I call allowInitialization() in order to tell the config source, that the bean is injectable now. Next time the ConfigSource is asked, it will be able to inject the bean using BeanProvider.injectFields.
public class DatabaseConfigSource implements ConfigSource {
private static boolean allowInit;
#Inject
private ConfigParameterProvider configParameterProvider;
#Override
public int getOrdinal() {
return 500;
}
#Override
public String getPropertyValue(String key) {
initIfNecessary();
if (configParameterProvider == null) {
return null;
}
return configParameterProvider.getProperty(key);
}
public static void allowInitialization() {
allowInit = true;
}
private void initIfNecessary() {
if (allowInit) {
BeanProvider.injectFields(this);
}
}
}
I have a request-scoped bean that holds all my config variables for type-safe access.
#RequestScoped
public class Configuration {
#Inject
#ConfigProperty(name = "myProperty")
private String myProperty;
#Inject
#ConfigProperty(name = "myProperty2")
private String myProperty2;
....
}
When injecting the Configuration class in a different bean, each ConfigProperty will be resolved. Since my custom DatabaseConfigSource has the highest ordinal (500), it will be used for property resolution first. If the property is not found, it will delegate the resolution to the next ConfigSource.
For each ConfigProperty the getPropertyValue function from the DatabaseConfigSource is called. Since I do not want to retreive the parameters from the database for each config property, I moved the config property resolution to a request-scoped bean.
#RequestScoped
public class ConfigParameterProvider {
#Inject
private ConfigParameterDao configParameterDao;
private Map<String, String> configParameters = new HashMap<>();
#PostConstruct
public void init() {
List<ConfigParameter> configParams = configParameterDao.findAll();
configParameters = configParams.stream()
.collect(toMap(ConfigParameter::getId, ConfigParameter::getValue));
}
public String getProperty(String key) {
return configParameters.get(key);
}
}
I could sure change the request-scoped ConfigParameterProvider to ApplicationScoped. However, we have a multi-tenant setup and the parameters need to be resolved per request.
As you can see, this is a bit hacky, because we need to explicitly tell the ConfigSource, when it is allowed to be instantiated properly (inject the bean).
I would prefer a standarized solution from DeltaSpike for using CDI in a ConfigSource. If you have any idea on how to properly realise this, please let me know.
Even though this post has been answered already I'd like to suggest another possible solution for this problem.
I managed to load properties from my db service by creating an #Signleton #Startup EJB which extends the org.apache.deltaspike.core.impl.config.BaseConfigSource and injects my DAO as delegate which I then registered into the org.apache.deltaspike.core.api.config.ConfigResolver.
#Startup
#Singleton
public class DatabaseConfigSourceBean extends BaseConfigSource {
private static final Logger logger = LoggerFactory.getLogger(DatabaseConfigSourceBean.class);
private #Inject PropertyService delegateService;
#PostConstruct
public void onStartup() {
ConfigResolver.addConfigSources(Collections.singletonList(this));
logger.info("Registered the DatabaseConfigSourceBean in the ConfigSourceProvider ...");
}
#Override
public Map<String, String> getProperties() {
return delegateService.getProperties();
}
#Override
public String getPropertyValue(String key) {
return delegateService.getPropertyValue(key);
}
#Override
public String getConfigName() {
return DatabaseConfigSourceBean.class.getSimpleName();
}
#Override
public boolean isScannable() {
return true;
}
}
I know that creating an EJB for this purpose basically produces a way too big overhead, but I think it's a bit of a cleaner solution instead of handling this problem by some marker booleans with static accessors ...
DS is using the java se spi mechanism for this which is not CD'Injectable'. One solution would be to use the BeanProvider to get hold of your DatabaseConfigSource and delegate operations to it.
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.
}
}
}