Quartz in Spring; jobDataAsMap serialization for multiple-use job bean - java

I have an extension to QuartzJobBean that takes two parameters:
public class FileListProcessorJob extends QuartzJobBean
{
transient static final Logger logger = Logger.getLogger(FileListProcessorJob.class);
FileListProcessor fileProcessor; // with setter
FileListProcessor fileProcessor2; // with setter
// ...
}
I have 4 quartz jobs in this application that use this bean; it is the number of times I have that processes a set of files from a folder, then does another set.
It works fine in my test environment, but when I moved it to development, I had to configure Quartz for a database datasource since it was to work in a cluster. When I did that, the runtime started telling me that "fileProcessor" was not serializable. I've tried to make it serializable, but the message is still there.
There are three different bean classes and four different beans loaded under fileProcessor; I've been over all of them to ensure they are serializable, but the message still appears. The message also appears to indicate that the log4j Logger is the non-serializable entity, but I can't see how that is. I made it transient in one pass, no difference.
The standard answers to the serializable problem I find on SO and elsewhere involve moving making a call within the job bean to the job execution context, passing in the reference through SchedulerContextAsMap. But, as near as I can tell, this depends on having globally unique names for the parameters to which to load the globally unique bean names, which doesn't work as I have this set up. I re-use the parameters since I re-use the bean itself.
I'm new to Spring design, but I thought this was the way it was supposed to work -- reusable components, configured with XML to avoid having similar classes slightly modified to do different things. So how can I make my 4 jobs work? Do I have to copy-and-paste them, then slightly modify the names so they're different, and unique in the configuration? Or is there some other piece I am missing and can use here?

There were two levels of problem to be solved; getting something to be serialized takes some painstaking examination and alteration of code, and the clustered environment writes serialized forms of the beans to the database and then uses them in preference to (or in place of, or addition to, I'm not sure) the spring/quartz configuration files. Once I got ALL the serialization necessaries done, and wiped the database records of all the jobs that had been stored there, it worked more like I had expected.

Related

Spring properties hot reloading

In a project, I have a org.apache.commons.configuration.PropertiesConfiguration object registered as a Bean, to provide configuration values around the application, with hot-reloading capabilities.
Example: I defined a DataSource singleton Bean. I then created a ReloadingDataSource object, which wraps and delegate to the "real" DataSource, and each time the configuration file changes, it is able to recreate it in a thread-safe manner.
I'd like to do something similar for simple properties values.
I'd like to create a simple, Autowireable object that delegate retrieval to the Apache PropertiesConfiguration Bean.
The usage should be similar to:
#Property("my.config.database")
private Property<String> database;
And the call site would simply be:
final String databaseValue = database.get()
You'll say, just pass around the PropertiesConfiguration object. Maybe you're right, but I'd like to provide another abstraction over that, a simpler-to-use one.
I know that with ProxyFactoryBean it is possible to create an AOP proxy for method calls. Is this the right path, or are there better alternatives? Maybe pure Spring AOP/AspectJ?
I don't want to use Spring Cloud or similar dependencies.
Spring Cloud will recreate the beans, so keep in mind whatever solution you come up with, if you have another bean which only reads this value once for instance when it is initiated, it won't re-initialize itself, that is the problem Spring Cloud Config takes care of.
AOP only works at the method level as I understand, so you can definitely intercept a call to somebean.getFoo(). But within somebean, there is no way to proxy calls to the variable itself: somebean.foo. You would have to reset foo every time your PropertiesConfiguration changed, and again keep in mind that, if anything else needs the new value of foo you would need to handle this or bite the bullet use Spring Cloud.
The overhead you have with changing stuff at run-time to avoid a re-deploy should really be thought carefully about. For Netflix, this makes sense because they have thousands and thousands of servers. But for smaller players I can't see the justification, the decision adds much complexity. Nightmare to test.
Do you test changing your configuration at run-time or accept the risk and assume it works?
Do you test changing from A -> B whilst under load of a user performing a transaction to the database?
Test other raise conditions where foo is changing?
Some things to think about.

Is there a way to store java variable/object in application context without xml or properties file

I want to store a particular variable (String or Object) in application context in spring boot application. But I don't want to use an xml or properties file for storing it.
There will be a function which will store the data in application context. I should be able to retrieve it, modify it, delete it or add more data.
Basically I want to store data in application context after its initialization has been done.
If you create a class and put #Configuration annotation over it, and declare some beans with #Bean annotation, they become application managed beans.
#Configuration
public class ConfigurationClass {
#Bean("myString")
public String getString() {
return "Hello World";
}
}
Then anywhere from your code you can call AnnotationConfigWebApplicationContext.getBean("myString") to get your bean.
Now there could be concurrency issues (as mentioned by davidxxx ). For that you can use SimpleThreadScope. Look at this link to learn how to register it with application context and where to place that annotation (or google it).
Or if you don't want to deal with that, then a #Scope("request") should help. The bean with #Scope("request") would be created for every new incoming request thus it’s thread safety is guaranteed since it’s created every time a new request comes in.
As a general way, you should avoid creating stateful services.
Storing application data in the server memory makes it harder to be resilient, autonomous but also distributed and scalable.
Besides, Spring Beans are not designed to be stateful.
If you do it, you may have race conditions without the required synchronization.
About your need, if you want really to have a stateful service at startup, create your own singleton instance and synchronize the methods that should be thread safe.
Then access it from anywhere.

Spring Boot: Conditional on database type

I have a Spring Boot application and want to inject specific repository implementations based on the type of the underlying SQL data source (defined using the spring.datasource.* properties).
I tried to use a custom conditional here, but unfortunately, when it is evaluated I cannot get the data source in order to check for the database type.
My condition currently looks like this:
#Order(Ordered.LOWEST_PRECEDENCE - 10)
class OnDatabaseTypeCondition implements Condition {
#Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
DataSource dataSource = context.getBeanFactory().getBean(DataSource.class);
// further matching code here
}
It should be used something like this:
#ConditionalOnDatabaseType(H2)
public class MyCustomImplementation implements MyRepository {
// Code
}
However, when the condition is evaluated, I get an exception that the data source is not defined:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [javax.sql.DataSource] is defined
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:348)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:335)
I assume that this is happening because the condition is already checked before all the beans are constructed. Is there any way that I can tell Spring that the data source has to be created before this condition is evaluated? Or is this just no possible using Spring conditions?
The use case I want to solve by doing is the following: The application can run with different types of databases, and some (like H2) do not certain functions like windowing functions. So I want to provide special queries for certain databases that may be slower, but still functionally correct. The idea for this approach was that these JDBC repositories should be easy to mark without the necessity of introducing specific Spring profiles, but just by looking at the underlying database (using org.springframework.jdbc.support.JdbcUtils).
Thanks
Some conditions are evaluated when the bean is actually created. If you want to check for the presence of a bean, you need to be very careful because any attempt to get a bean at that stage will lead to an early initialization. That's the first problem.
The second problem is that your configuration (app configuration) always run completely before the auto-configuration. If Spring Boot has to decide if it must create a DataSource, it should give the app configuration a chance to provide one.
The only way you could implement that is via auto-configuration, making sure that your auto-configuration runs after the ones that are supposed to provide the bean you're looking for ( #AutoconfigureAfter). Regardless I wouldn't do a straight call to the context like that. Check OnBeanCondition to see how Spring Boot does that thing itself. So you can't add such condition to your app configuration or to your components scanned by component scanning.
Having said that, the use case looks quite weird to me. Maybe we could take a step back and you could explain why you need to do this.
As for the specific question, have you considered checking the JDBC connection string?
You could check the properties (spring.datasource.url) to see if it's h2 or not.
E.g. ${spring.datasource.url}.startsWith('jdbc:h2:')
The reason is that properties are available during autoconfiguration. In fact, H2 with a temporary database is instantiated as DataSource when the corresponding properties are not configured for a different database.

Java: when to serialize non-serializated objects or put them to transient?

I am puzzled by non-serialized fields, objects in a Serialized object at my new work.
What should be serialized or what should be marked as transient for serialization?
Here is an example:
#Stateless
public class NonSerializedThingStateless{
...
}
#RequestScoped
public class NonSerializedThingRequestScoped{
...
}
#Named
#SessionScoped
public class SerializedBean implements Serializable{
#Inject
private NonSerializedThingRequestScoped nstrs;
#Inject
private NonSerializedThingStateless nsts;
private List<Something> list; //or something else like POJO
...
}
Is there a good and simple way where I can tell when I should serialize the Injected or used classes or a guideline?
Is it true I have to choose between serialization and putting things to transient, or are there other ways?
First, a word of warning: You will probably want to use #Inject only for the simple cases (usually that would be singletons). For everything else, autowiring works but it can get confusing very fast.
That said, the rule for transient is simple: When you read the object (deserialize), do you still have everything you need to recreate the original state?
If an object depends on the current request, the answer is probably no: At the time when the bean is read from the stream, the request will be long gone.
In web applications, quite often session-scoped variables will be declared as implements Serializable. There are a few common reasons for this:
A clustered environment (there is more than one app server running your web application) can be configured for session replication. In this case, when a user session is changed (eg I add an item to my shopping cart), that change is pushed to all the other app servers in the cluster. These application servers run in different JVMs, and need a way of passing Java objects from one JVM to another. To do this they serialise the session into a stream of bytes and write the bytes to a socket.
When a single app server is shutdown (perhaps to have a new web app version deployed), it can be configured to preserve sessions, which means that it will typically write the sessions to the disk. When it starts up again, the sessions are read from the disk and recreated in the running web application. Again to do this, the session is serialised to a byte[] and written to the file system.
Think about the above two examples when deciding whether a field should be serialized or transient. If we do this, then there are a few simple rules. Generally:
Anything request-scoped should made transient. Eg the search text a user typed in a search field. This information really doesn't need to be persisted, as it's only relevant to the current request.
Anything stateless should be made transient. The classic example here is a logger. A logger doesn't need to serialised as there's no state that should be saved. The code will continue to run just fine if a new logger was created!
Anything session-scoped should be serialized. For example, user preferences or items added to a shopping cart.
So to answer your questions:
Is there a good and simple way where I can tell when I should serialize the Injected or used classes or a guideline?
Think about why sessions are serialized (ie what I wrote above) and determine if it makes sense to serialize or not, regardless of whether a field is injected.
Is it true I have to choose between serialization and putting things to transient, or are there other ways?
If you are definitely going to be serializing the sessions; then yes, you have to make the choice of what should be serialized and what should be transient. However, if you are not running in a clustered environment, you are not saving sessions to disk on shutdown, and there are no other problems; then it is perfectly reasonable not to make anything Serializable as no serialisation is going to take place!

Why is buildSessionFactory() deprecated?

Why is buildSessionFactory() replaced by buildSessionFactory(ServiceRegistry)? What is the importance of ServiceRegistry?
The reasons for this are explained on Hibernate's Jira
https://hibernate.onjira.com/browse/HHH-2578
Currently a SessionFactory is built by throwing a bunch of stuff into a Configuration object, stirring it, letting it come to a boil, and then pulling out the SessionFactory. In seriousness, there are a few problems with the way we currently operate within a Configuration and how we use it to build a SessionFactory:
The general issue that there is no "lifecycle" to when various pieces of information will be available. This is an important omission in a number of ways:
1) consider schema generation. currently we cannot even know the dialect when a lot of db object names are being determined. this would be nice because it would allow us to transparently handle table/column names which are also keywords/reserved-words in the dialect, for example.
2) static-ness of types and the type-mappings. Because we currently have nothing to which to scope them. Ideally a type instance would be aware of the SessionFactory to which it is bound. Instead, what we have now is to change API methods quite a lot of the time to add in the SessionFactory as a passed parameter whenever it is discovered that it is needed.
3) also, most (all?) of the "static" configuration parameters in Hibernate are currently required to be so because of their use from within these static types; thus scoping types would allow us to also scope those config parameters (things like bytecode-provider, use of binary streams, etc).
Ideally what I see happening is a scheme where users build a org.hibernate.cfg.Settings (or something similiar) instance themselves. Additionally they would apply metadata to a registry of some sort (lets call it MetadataRegistry for now). Then in order to build a SessionFactory, they would supply these two pieces of information (via ctor? via builder?). The important aspect though is that the information in MetadataRegistry would not be dealt with until that point in time, which would allow us to guarentee that resolving schema object names, types, etc would have access to the runtime Settings (and specifically the dialect)
You can read also comments on this one: https://hibernate.onjira.com/browse/HHH-7580
Its too much to copy paste and I guess Jira won't go down so this answer should be valid.

Categories