I configure first_cache and it works fine.
But when I want add second_cache in FirstCasheResolver CacheOperationInvocationContext has only one cache while RedisCacheManager has two caches.
Also SecondCacheResolver even not triggered.
Please help me.
Here is my CacheConfiguration class
#EnableCaching
#Configuration
public class CacheConfiguration {
public static final String FIRST_CACHE_NAME = "first_cache";
public static final String SECOND_CACHE_NAME = "second_cache";
private int defaultTokenExpirationTime = 1000;
#Bean
public RedisCacheManager redisCacheManager(RedisConnectionFactory redisConnectionFactory) {
return RedisCacheManager.builder(redisConnectionFactory)
.cacheDefaults(getDefaultRedisCacheConfiguration())
.withCacheConfiguration(FIRST_CACHE_NAME, getCustomRedisCacheConfiguration())
.withCacheConfiguration(SECOND_CACHE_NAME, getCustomRedisCacheConfiguration())
.build();
}
private RedisCacheConfiguration getDefaultRedisCacheConfiguration() {
return RedisCacheConfiguration.defaultCacheConfig().disableCachingNullValues();
}
private RedisCacheConfiguration getCustomRedisCacheConfiguration() {
return RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofSeconds(defaultTokenExpirationTime));
}
#Bean("firstCacheResolver")
public CacheResolver firstCacheResolver(RedisCacheManager redisCacheManager) {
return new FirstCacheResolver(redisCacheManager);
}
#Bean("secondCacheResolver")
public CacheResolver secondCacheResolver(RedisCacheManager redisCacheManager) {
return new SecondCacheResolver(redisCacheManager);
}
}
Here is my FirstCacheResolver class
public class FirstCacheResolver extends SimpleCacheResolver {
public FirstCacheResolver(CacheManager cacheManager) {
super(cacheManager);
}
#Override
public Collection<? extends Cache> resolveCaches(CacheOperationInvocationContext<?> context) {
return super.resolveCaches(context).stream().toList();
}
}
here super.resolveCaches(context) returns list only one first_cache but CacheManager has first_cache and second_cache
Here is my SecondCacheResolver class
public class SecondCacheResolver extends SimpleCacheResolver {
public SecondCacheResolver(CacheManager cacheManager) {
super(cacheManager);
}
#Override
public Collection<? extends Cache> resolveCaches(CacheOperationInvocationContext<?> context) {
return super.resolveCaches(context).stream().toList();
}
}
this resolveCaches() method even not triggered
here is usage of both caches. They
public class FirstClass {
#Cacheable(
cacheNames = {CacheConfiguration.FIRST_CACHE_NAME},
key = "#params.get('first').get(0)",
cacheResolver = "firstCacheResolver"
)
public int getFirst(MultiValueMap<String, Object> params) {
// some logic
}
}
public class SecondClass {
#Cacheable(
cacheNames = {CacheConfiguration.SECOND_CACHE_NAME},
key = "#params.get('second').get(0)",
cacheResolver = "secondCacheResolver"
)
public int getSecond(MultiValueMap<String, Object> params) {
// some logic
}
}
cacheManager in debug
I try implement two caches with custom CacheResolvers.
Related
Help me in the following code and how to used the backup on the Hazelcast
migration of the hazelcast 3.x.x to 5.x.x
package com.hazelcast.map;
import com.hazelcast.core.HazelcastInstance;
import com.hazelcast.core.HazelcastInstanceAware;
import com.hazelcast.nio.serialization.impl.BinaryInterface;
import java.util.Map;
// Interface AbstractEntryProcessor
#BinaryInterface
public abstract class AbstractEntryProcessor<K,V> implements EntryProcessor<K,V> {
private final EntryBackupProcessor<K,V> entryBackupProcessor;
// Non Parameterize Constructor
public AbstractEntryProcessor() {
this(true);
}
// Parameterize Constructor AbstractEntryProcessor
public AbstractEntryProcessor(boolean applyOnBackup) {
if (applyOnBackup) {
entryBackupProcessor = new EntryBackupProcessorImpl();
} else {
entryBackupProcessor = null;
}
}
//EntryBackupProcessor
#Override
public final EntryBackupProcessor getBackupProcessor() {
return entryBackupProcessor;
}
// class EntryBackupProcessorImpl
private class EntryBackupProcessorImpl implements EntryBackupProcessor<k,V>, HazelcastInstanceAware {
// generated for EntryBackupProcessorImpl which doesn't implement HazelcastInstanceAware
static final long serialVersionUID = -5081502753526394129L;
#Override
public void processBackup(Map.Entry<K,V> entry) {
process(entry);
}
#Override
public void setHazelcastInstance(HazelcastInstance hazelcastInstance) {
final AbstractEntryProcessor<k,V> outer = AbstractEntryProcessor.this;
if (outer instanceof HazelcastInstanceAware) {
((HazelcastInstanceAware) outer).setHazelcastInstance(hazelcastInstance);
}
}
}
}
How to used the backup methods in 5.x.x versons of series
how to used the backup in the above question ?
This should work:
public abstract class AbstractEntryProcessor implements EntryProcessor, HazelcastInstanceAware {
protected transient HazelcastInstance hazelcastInstance;
private final boolean applyOnBackup;
// Non Parameterize Constructor
public AbstractEntryProcessor() {
this(true);
}
// Parameterize Constructor AbstractEntryProcessor
public AbstractEntryProcessor(boolean applyOnBackup) {
this.applyOnBackup = applyOnBackup;
}
//EntryBackupProcessor
#Override
public final EntryProcessor getBackupProcessor() {
if (!applyOnBackup || this instanceof ReadOnly) {
return null;
}
return this;
}
#Override
public void setHazelcastInstance(HazelcastInstance hazelcastInstance) {
this.hazelcastInstance = hazelcastInstance;
}
}
I have an interface called HeaderProvider and its implementations like this,
interface HeaderProvider {
Map<String, String> getHeaders();
}
class AHeaderProvider implements HeaderProvider {
...
}
class BHeaderProvider implements HeaderProvider {
...
}
The implementations are Spring managed beans. Now I have an enum URLType
enum URLType{
A,
B....
}
Is there any way I can have a method inside the enum like HeaderProvider getHeaderProvider() which will return the correct implementation?
Just add a HeaderProvider member to the enum
public enum URLType {
A(new AHeaderProvider()), B(new BHeaderProvider());
private HeaderProvider provider;
private URLType(HeaderProvider provider) {
this.provider = provider;
}
public HeaderProvider getHeaderProvider() {
return provider;
}
}
I think you can do like this.
#Component
public class AHeaderProvider implements HeaderProvider, InitializingBean {
private static HeaderProvider headerProvider;
public static HeaderProvider getHeaderProvider() {
return headerProvider;
}
#Override
public void afterPropertiesSet() throws Exception {
headerProvider = this;
}
#Override
public Map<String, String> getHeaders() {
return new HashMap<>();
}
}
#Component
public class BHeaderProvider implements HeaderProvider, InitializingBean {
private static HeaderProvider headerProvider;
public static HeaderProvider getHeaderProvider() {
return headerProvider;
}
#Override
public void afterPropertiesSet() throws Exception {
headerProvider = this;
}
#Override
public Map<String, String> getHeaders() {
return new HashMap<>();
}
}
public enum UrlType {
A(AHeaderProvider.getHeaderProvider()),
B(BHeaderProvider.getHeaderProvider());
private HeaderProvider headerProvider;
UrlType(HeaderProvider headerProvider) {
this.headerProvider = headerProvider;
}
public HeaderProvider getHeaderProvider() {
return headerProvider;
}
}
I make static variable like this in spring.
public class A {
private static final Map<String, Session> listMap = new HashMap<>();
public static Map<String> getMap() { return this.listMap.values() }
public static void addMap(String name, Session s) { return this.listMap.put(name, s) }
}
I save in service layer.
#Slf4j
public class BService {
public void addSession(String name, Session s) {
A.addMap("a", s);
log.info("added!");
}
}
After saving it, I used it in custom appender.(https://www.baeldung.com/log4j2-custom-appender)
#Plugin(
name = "MapAppender",
category = Core.CATEGORY_NAME,
elementType = Appender.ELEMENT_TYPE)
public class MapAppender extends AbstractAppender {
private ConcurrentMap<String, LogEvent> eventMap = new ConcurrentHashMap<>();
protected MapAppender(String name, Filter filter) {
super(name, filter, null);
}
#PluginFactory
public static MapAppender createAppender(
#PluginAttribute("name") String name,
#PluginElement("Filter") Filter filter) {
return new MapAppender(name, filter);
}
#Override
public void append(LogEvent event) {
Map<> resultMap = A.getMap();
send()
}
}
However, when the appender's append() method is executed, A.getMap() return nothing(size 0). (A.getMap() return correctly in service layer.)
Why is the static value different?..
listMap is loaded when you call addSessionso it is empty When append() method is called
My spring version is 1.5.2, spring-mybatis-start version is 1.3.2,
I set mybatis.configuration.map-underscore-to-camel-case=true in properties.
But the MAP I returned was not converted to Camel named
Here is my configuration
mybatis.configuration.map-underscore-to-camel-case=true
The problem has been sovled,the plan is as follows
public class CustomWrapper extends MapWrapper{
public CustomWrapper(MetaObject metaObject, Map<String, Object> map) {
super(metaObject, map);
}
// useCamelCaseMapping is map-underscore-to-camel-case field
#Override
public String findProperty(String name, boolean useCamelCaseMapping) {
if(useCamelCaseMapping){
return CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL,name);
}
return name;
}
}
public class MapWrapperFactory implements ObjectWrapperFactory {
#Override
public boolean hasWrapperFor(Object object) {
return object != null && object instanceof Map;
}
#Override
public ObjectWrapper getWrapperFor(MetaObject metaObject, Object object) {
return new CustomWrapper(metaObject,(Map)object);
}
}
#Configuration
public class MybatisConfig {
#Bean
public ConfigurationCustomizer mybatisConfigurationCustomizer(){
return new ConfigurationCustomizer() {
#Override
public void customize(org.apache.ibatis.session.Configuration configuration) {
configuration.setObjectWrapperFactory(new MapWrapperFactory());
}
};
}
}
I made a DAO class with factory method and the specific DAO returns singleton, a single instance of the DAO. But I been tracing it and its being created but I try to call on it and it always null.
Just to explain the storage factory
I call on DAOFactory to get RAMDAOFactory to get to RAMUserDAO
If there is better way to handle RAM, Serialization and SQL type DAOs or CRUD please let me know.
class that I'm calling the storage from.
public class Registration
{
private UserDAO userStorage;
private static Logger log = LogClass.getLog();
Registration(DAOFactoryType typeDataStorage)
{
userStorage = DAOFactory.getDAOFactory(typeDataStorage).getUserDAO();
log.trace("insdie Reg");
}
void addUser(String userName, String password, UserType... args)
throws Exception
{
List<UserType> userTypes = new ArrayList<UserType>(args.length);
for (UserType userType : args)
{
log.trace("userType " + userType);
userTypes.add(userType);
}
User newUser = new DefaultUser(userName, password, userTypes);
log.trace("newUser " + newUser);
if (userStorage != null)
{
userStorage.insert(newUser);
}
else
{
log.trace("userStorage null");
}
}
}
This is my DAOFactory
public abstract class DAOFactory
{
private static Logger log = LogClass.getLog();
public abstract TradeDAO getTradeDAO();
public abstract UserDAO getUserDAO();
public abstract LogDAO getLogDAO();
public static DAOFactory getDAOFactory(DAOFactoryType factoryType)
{
switch (factoryType)
{
case SQL:
return new SQLDAOFactory();
case RAM:
log.trace("insdie RAM");
return new RAMDAOFactory();
case SERIAL:
return new SerialDAOFactory();
default:
return null;
}
}
}
RAMDAOFactory
public class RAMDAOFactory extends DAOFactory
{
private static Logger log = LogClass.getLog();
private TradeDAO ramTradeDAO;
private UserDAO ramUserDAO;
private LogDAO ramLogDAO;
public RAMDAOFactory()
{
log.trace("insdie RAMDAOFactory");
RAMUserDAO.getRAMUserDAO();
RAMTradeDAO.getRAMTradeDAO();
RAMLogDAO.getRAMLogDAO();
}
#Override
public TradeDAO getTradeDAO()
{
return ramTradeDAO;
}
#Override
public UserDAO getUserDAO()
{
return ramUserDAO;
}
#Override
public LogDAO getLogDAO()
{
return ramLogDAO;
}
}
This is my UserDAO
public class RAMUserDAO implements UserDAO
{
/*
* Map<Integer, List<byte[]>> userHash; List<byte[]> arrayHashSalt;
*/
private static RAMUserDAO userDAO = null;
private Map<String, User> userList;
private static Logger log = LogClass.getLog();
private RAMUserDAO()
{
userList = new HashMap<String, User>();
log.trace("insdie RAMUserDAO constructor");
}
public static RAMUserDAO getRAMUserDAO()
{
log.trace("insdie getRAMUserDAO");
if(userDAO == null) {
log.trace("insdie new RAMUserDAO()");
userDAO = new RAMUserDAO();
}
/*if (userDAO == null)
{
synchronized (RAMUserDAO.class)
{
if (userDAO == null)
{
userDAO = new RAMUserDAO();
}
}
}*/
return userDAO;
}
#Override
public void insert(User user) throws Exception
{
log.trace("insdie insert");
userList.put(user.getUserName(), user);
}
}
The oversight was in RAMDAOFactory and fix was:
public class RAMDAOFactory extends DAOFactory
{
private static Logger log = LogClass.getLog();
#Override
public TradeDAO getTradeDAO()
{
return RAMTradeDAO.getRAMTradeDAO();
}
#Override
public UserDAO getUserDAO()
{
return RAMUserDAO.getRAMUserDAO();
}
#Override
public LogDAO getLogDAO()
{
return RAMLogDAO.getRAMLogDAO();
}
}
You've called the methods
public RAMDAOFactory()
{
log.trace("insdie RAMDAOFactory");
RAMUserDAO.getRAMUserDAO();
RAMTradeDAO.getRAMTradeDAO();
RAMLogDAO.getRAMLogDAO();
}
but you haven't assigned their value to anything
#Override
public UserDAO getUserDAO()
{
return ramUserDAO;
}
Either always call
RAMUserDao.getRAMUserDAO();
when you want to return the UserDAO or assign it to ramUserDAO and return that.