Different Java proxy based frameworks with pros and cons.

Today there are several tools that can be used to manipulate bytecode, ranging from very low-level tools such as ASM, which require you to work at the bytecode level, to high level frameworks such as CGlib, AspectJ, which allow you to write pure Java. Ofcourse each framework have there own limitations in creating proxies.

For the moment, I just want to provide a quick summary on the pros and cons of proxy frameworks available. Hope everyone knows about the GOFProxy design pattern.

JDK dynamic proxies:

The JDK dynamic Proxy relies heavily on interface based implementations.JDK comes with the class java.lang.reflect.Proxy that allows you to create a dynamic proxy for a given interface. The InvocationHandler that sits behind the dynamically created class is called every time the application invokes a method on the proxy. Hence you can control dynamically what code is executed before the code of some framework or library is called.

Dynamic proxies can be used for many different purposes, e.g. database connection and transaction management, dynamic mock objects for unit testing, and other AOP-like method intercepting purposes.

Hibernate for lazy loading entities, Spring for AOP, LambdaJ for DSL, only to name a few: they all use their hidden magic. What are they? They are… Java’s dynamic proxies.

Limitation of JDK Dynamic proxy can only proxy by interface (so your target class needs to implement an interface).Any interface method is then forwarded to an InvocationHandler.If class does not implemented from interface then you will see ClassCastException.

Sample code to create proxy using JDK proxies.


MyInterface proxy = (MyInterface) Proxy.newProxyInstance(
                MyInterface.class.getClassLoader(),
                new Class[]{MyInterface.class},
                new InvocationHandler(){
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        if (method.getName().equals("your method name")) {
                            // do want ever magic you want...
                        }
                    }
                });
The invoke method will intercept all method calls on your proxied object.

CGLib proxies :

Java proxies are runtime implementations of interfaces. Objects do not necessarily implement interfaces, so Java proxies fail to provide an answer for a class not implemented from interface.

That's where CGlib came out.CGlib is a third-party framework, based on bytecode manipulation provided by ASM that can help with the previous limitations. 


     1. The proxies are created by sub-classing the actual class. This means wherever an instance of the class is used it is also possible to use the CGLib proxy.
     2. The class needs to provide a default constructor, i.e. without any arguments. Otherwise,you'll get an IllegalArgumentException: "Superclass has no null constructors but no arguments were given." This makes constructor injection impossible.
     3. The proxying does not work with final methods since the proxy subclass can not override the class' implementation.
     4. The CGLib proxy is final, so proxying a proxy does not work. You will get an IllegalArgumentException.
     5. Two objects are created (the instance of the class and the proxy as instance of a sub class) the constructor is called twice.
     6. Documentation of CGlib is not complete.
     7. The proxies are not Serializable.
     8. You will need add CGLIB binaries on your classpath or dependencies.
     9. Furthermore, cglib can improve performance by specialized interceptions like FixedValue,NoOp,LazyLoader...
CGlib introduced many callback handlers for better performance.Please go with my previous post "Creating Proxies Dynamically Using CGLIB Library with examples".

Spring AOP: CGLIB or JDK Dynamic Proxies ?

Spring AOP uses either JDK dynamic proxies or CGLIB to create the proxy for a given target object. (JDK dynamic proxies are preferred whenever you have a choice). If the target object to be proxied implements at least one interface then a JDK dynamic proxy will be used. All of the interfaces implemented by the target type will be proxied. If the target object does not implement any interfaces then a CGLIB proxy will be created. 

If you want to force the use of CGLIB proxying (for example, to proxy every method defined for the target object, not just those implemented by its interfaces) you can do so.



ASM :

CGLIB and almost all other libraries are built on top of ASM which itself acts on a very low level. This is a show-stopper for most people as you have to understand the byte code and a little bit of the JVMS to use it properly. But mastering ASM is most certainly very interesting. Note however that while there is a great ASM 4 guide, in some part of the API the javadoc documentation can be very concise if it is present at all, but it is being improved. It closely follows JVM versions to support new features.

Javassist :

The javadoc of Javassist is way better than that of CGLIB. The class engineering API is OK, but Javassist is not perfect either. In particular, the ProxyFactory which is the equivalent of the CGLIB's Enhancer suffer from some drawbacks too, just to list a few :

      1. Bridge method are not fully supported (ie the one that are generated for covariant return types).
      2. ClassloaderProvider is a static field instead, then it applies to all instances within the same classloader.
      3. Custom naming could have been welcome (with checks for signed jars).
      4. There is no extension point and almost all methods of interest are private, which is cumbersome if we want to change some behavior.
      5. While Javassist offer support for annotation attributes in classes, they are not supported in ProxyFactory. 

On the aspect oriented side, one can inject code in a proxy, but this approach in Javassist is limited and a bit error-prone .

      1. aspect code is written in a plain Java String that is compiled in opcodes.
      2. no type check.
      3. no generic.
      4. no lambda.
      5. no auto-(un)boxing

Also Javassist is recognized to be slower than Cglib. This is mainly due to its approach of reading class files instead of reading loaded classes such as CGLIB does. And the implementation itself is hard to read to be fair ; if one requires to make changes in the Javassist code there's many chances to break something.

Byte Buddy :

Byte Buddy is a rather new library but provides any functionality that CGLIB provides. Byte Buddy can be fully customized down to the byte code level and comes with an expressive domain specific language that allows for very readable code.

It supports all JVM bytecode versions, including Java 8 semantic changes of some opcodes regarding default methods.

      1. ByteBuddy don't seem to suffer from the drawbacks other libraries have.
     2. Highly configurable.
     3. Quite fast (benchmark code).
     4. Type safe.
     5. Type safe callbacks.
    6. Very well documented.
    7. Lots of example.
    8. Annotation driven (flexible).
    9. Available as an agent.
    10. Clean code, 93% test coverage

You can find more details on the benchmark in Byte Buddy's tutorial, where Byte Buddy is a more modern alternative to cglib. Also, note that cglib is no longer under active development.

Here are some metrics for implementing an interface with 18 stub methods:
Byte Buddy        CGlib                 Javassist         JDK proxy         
Creation 0.234 0.613 0.391 0.309
invocation       0.002   0.019  0.027 0.003 

The time is noted in nanoseconds.

In fact there are other proxy frameworks like BCEL, AspectJ, JiteScript, Proxetta are not discussed in this post as there are not much familiar.

To summarize, out of all frameworks Byte Buddy is a most modern(as of 2015) proxy framework with precise documentation and with various examples.Mockito used CGlib over years,in recent time mockito is replacing CGLIB by Byte Buddy.



Ehcache 3.0 new API fundamentals

It’s been 5 years since Ehcache released Ehcache 2.0.Now Ehcache 3.0 is one of the most feature rich caching APIs out there.In the meantime while some caching solutions took very different approaches on it all, the expert group on JSR-107, Terracotta included, put great efforts in trying to come up with a standard API in 3.0.Below are the features introduced in Ehcache 3.0

1) Ehcache 3.0 will likely “extend” the specification of JSR-107.
2) Ehcache 2.0 constrain caches on-heap or on-disk.3.0 introduced more tiers to cache data in (off-heap, Terracotta clustered).
3) 3.0 new API is ready for the immediate future that is Java 8.
4) Ehcache 3.0 API supporting Lamdas.
5) Introduced BootstrapCacheLoader (sync/async),ehanced Statistics,Search & Transaction.
6) Introduced Write Through,Write Behind,Read Through & Refresh Ahead Features.
7) Many more......

Today, let me explain fundamentals of ehcache 3.0 using a simple demo program.Before going to ehcache 3.0,I recommend to understand basics of ehcache 2.x api,please go with my previous post.

Ehcahce can build with two types of configurations.
      1) XMLConfiguration.
      2) Building configuration using API.

Building cache using XMLConfiguration :
Below are the dependencies required to use Ehcache 3.0.

<dependency>
            <groupId>org.ehcache</groupId>
            <artifactId>ehcache</artifactId>
            <version>3.0.0.m3</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.5.6</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-jdk14</artifactId>
            <version>1.5.6</version>
        </dependency>

XML Configuration (userCache.xml):

<ehcache:config
        xmlns:ehcache="http://www.ehcache.org/v3"
        xmlns:jcache="http://www.ehcache.org/v3/jsr107">
    <!--<ehcache:service>
        <ehcache:default-serializers>
            <ehcache:serializer type="org.ehcache.spi.serialization.DefaultSerializationProvider">
            </ehcache:serializer>
        </ehcache:default-serializers>
    </ehcache:service>
    -->
    <ehcache:cache-template name="myTemplate">
        <ehcache:expiry>
            <ehcache:tti unit="minutes">5</ehcache:tti>
        </ehcache:expiry>
        <ehcache:eviction-prioritizer>LRU</ehcache:eviction-prioritizer>
        <ehcache:heap size="200" unit="entries"/>
    </ehcache:cache-template>
    <ehcache:cache alias="defaultCache" usesTemplate="myTemplate">
        <ehcache:key-type copier="org.ehcache.internal.copy.SerializingCopier">java.lang.Integer</ehcache:key-type>
        <ehcache:value-type copier="org.ehcache.internal.copy.SerializingCopier">com.newehcache.model.User
        </ehcache:value-type>
    </ehcache:cache>
    <ehcache:cache alias="userCache" usesTemplate="myTemplate">
        <ehcache:key-type copier="org.ehcache.internal.copy.SerializingCopier">java.lang.Integer</ehcache:key-type>
        <ehcache:value-type copier="org.ehcache.internal.copy.SerializingCopier">com.newehcache.model.User
        </ehcache:value-type>
        <ehcache:expiry>
            <ehcache:ttl unit="minutes">2</ehcache:ttl>
        </ehcache:expiry>
        <ehcache:eviction-veto>com.newehcache.evictionveto.UserEvictionVeto</ehcache:eviction-veto>
        <ehcache:eviction-prioritizer>LFU</ehcache:eviction-prioritizer>
        <ehcache:integration>
            <ehcache:listener>
                <ehcache:class>com.newehcache.listener.UserListener</ehcache:class>
                <ehcache:eventFiringMode>SYNCHRONOUS</ehcache:eventFiringMode>
                <ehcache:eventOrderingMode>ORDERED</ehcache:eventOrderingMode>
                <ehcache:eventsToFireOn>CREATED</ehcache:eventsToFireOn>
            </ehcache:listener>
        </ehcache:integration>
        <ehcache:heap size="500" unit="mb"></ehcache:heap>
    </ehcache:cache>

</ehcache:config>

With this XML file you can configure a CacheManager at creation time.Brief explanation of configuration xml.
The root element of our XML configuration is config.One <config> element is one Cachemanager.With Ehcache 3.0, however, you may create multiple
CacheManager instances using the same XML configuration file.There are three elements under config
1) Service : Service is extension point for specifying CacheManager managed services.Each Service defined in this way is managed with the
same lifecycle as the CacheManager.In above examples I am using default Services,that is DefaultSerializationProvider or org.ehcache.spi.copy.DefaultCopyProvider.
2) CacheTemplate : CacheTemplate is for <cache> elements to inherit from.A <cache> element that references a <cache-template> by its name. A <cache> can override these properties as it needs.
In the above xml,we declared a template called myTemplate with basic details like, cache expires if it idle for 5 mins and Heap can hold atmost 200 entires.
And in the userCache,we overrided template values by increasing HEAP entries and decreasing expire time.
3) Cache : A <cache> element represent a Cache instance that will be created and managed by the CacheManager.
Each <cache> requires the alias attribute which is uniqully identified by CacheManager.There are multiple elements inside cache
    1) key-type : Defines the type for the key in the cache.Takes a fully qualified class name.
    2) value-type: Defines the type for the Value in cache.Takes a fully qualified class name.
    3) expiry : Defines expiry for the Cache.You can add any of the expire as below.
        1) class : You can create user defined expire stategy by implementing org.ehcache.expiry.Expiry.
        2) tti : Cache should expire if not accessed for the defined time.Supports all types of time units.
        3) ttl : Cache should expire after the defined time.Supports all types of time units.
        4) none : Cache should never expire.Default is none.
    4) eviction-veto : UserDefined eviction-veto which implements org.ehcache.config.EvictionVeto.
    5) eviction-prioritizer :  Policy would be enforced upon reaching the maxEntriesLocalHeap limit. Default policy is Least Recently Used (specified as LRU). Other policies available - First In First Out (specified as FIFO) and Less Frequently Used (specified as LFU)
    6) integration : You can Integrate loaderwriters,writebehind or listener to the cache.In our xml we defined userListner which triggers event which adding entry into cache.
    7) heap : Heap only cache.No of entires in the HEAP allowed.
There are many such attributes in xml configuration,please go through schema definition.

User Model Class :

We use below simple model class for caching.
public class User implements Serializable{
    private Integer userid;
    private String username;
    private String password;
    private String role;
    private Integer tenantid;
    public User(Integer userid, String username, String password, String role, Integer tenantid) {
        this.userid = userid;
        this.username = username;
        this.password = password;
        this.role = role;
        this.tenantid = tenantid;
    }
//setters & getters & toString
}

UserListener :


public class UserListener implements CacheEventListener {
    @Override
    public void onEvent(CacheEvent event) {
        Integer id = (Integer)event.getKey();
        User user = (User)event.getNewValue();
        //do some work when event is triggered.
        if(user.getTenantid() > 50)
        {
            System.out.println("Listener invoked when adding user" + user.getUserid());
        }
    }
}

UserEvictionVeto :


public class UserEvictionVeto implements EvictionVeto {
    @Override
    public boolean test(Object value) {
        User user = (User) value;
        if(user.getTenantid() > 60)
        {
            return true;
        }
        return false;
    }
}

NewEhcacheXMLConfigurationDemo : 

This is the Demo class,which takes userCache.xml configuration and builds cacheManager that intern builds cache.

public class NewEhcacheXMLConfigurationDemo {

    public static int count = 0;
    public static void main(String[] args) {

        try {
            URL url = SimpleEhcacheDemo.class.getClassLoader().getResource("ehcache/userCache.xml");
            final CacheManager cacheManager = new EhcacheManager(new XmlConfiguration(url, SimpleEhcacheDemo.class.getClassLoader()));
            cacheManager.init();
            final Cache<Integer, User> userCache = cacheManager.getCache("userCache", Integer.class, User.class);
            int noOfThreads = 2;
            ExecutorService executorService = Executors.newFixedThreadPool(noOfThreads);
            executorService.submit(new Runnable() {
                @Override
                public void run() {
                    String threadName = "thread_1";
                    //adding users into cache
                    for (int i = 0; i < 3; i++) {
                        int userID = getCount();
                        addUser(userCache, userID);
                        System.out.println("Added user"+ userID + " to userCache using in " + threadName);
                    }
                    int i = 1;
                    while (i <= count) {
                        //any random value between 1 to 45 sec
                        int sleepTime = getRandomSleepTime(1000, 45000);
                        System.out.println(threadName + " will sleep during " + sleepTime + " milliseconds");
                        try {
                            Thread.currentThread().sleep(sleepTime);
                        } catch (InterruptedException e) {
                            //do nothing
                        }
                        boolean exist = userCache.containsKey(i);
                        System.out.println("user" + i + (exist ? " exist" : " not exist") + " using " + threadName);
                        i++;
                    }
                }
            });
            executorService.submit(new Runnable() {
                @Override
                public void run() {
                    String threadName = "thread_2";
                    //adding users into cache
                    for (int i = 0; i < 3; i++) {
                        int userID = getCount();
                        addUser(userCache, userID);
                        System.out.println("Added user"+ userID + " to userCache using in " + threadName);
                    }
                    int i = 1;
                    while (i <= count) {
                        //any random value between 1 to 60 sec
                        int sleepTime = getRandomSleepTime(1000, 60000);
                        System.out.println(threadName + " will sleep during " + sleepTime + " milliseconds");
                        try {
                            Thread.currentThread().sleep(sleepTime);
                        } catch (InterruptedException e) {
                            //do nothing
                        }
                        boolean exist = userCache.containsKey(i);
                        System.out.println("user" + i + (exist ? " exist" : " not exist") + " using " + threadName);
                        i++;
                    }
                }
            });
            try {
                //waiting until executor threads are done.
                executorService.shutdown();
                while (!executorService.awaitTermination(24L, TimeUnit.HOURS)) {
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            userCache.clear();
            cacheManager.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

        System.out.println("Bye bye....");
    }
    private static void addUser(Cache<Integer, User> userCache, int id) {
        User user = new User(id, "user" + id, "user" + id, "user", new Random().nextInt(100) + 1);
        System.out.println(user);
        userCache.put(id, user);
    }
    public static int getCount() {
        return ++count;
    }
    private static int getRandomSleepTime(int min, int max) {
        return min + (int) (Math.random() * ((max - min) + 1));
    }
}

Brief explanation above code, two threads operating on a single cache(userCache) and each thread add 3 users into cache.First thread will add three users and then go to sleep for time 0-45sec while reading each user from cache.Mean while second thread will add three users and will go to sleep for (0 - 60 sec) while reading each user from cache. If elements in the cache are not operated for more then  expire time then they will evict from cache.In above example as threads are going to sleep,some users are not touched hence they may be evicted from cache.Also notice listener is invoking when user is added into cache.

You may see different outputs for each run of above code.Below is one

User{userid=1, username='user1', password='user1', role='user', tenantid=64}
User{userid=2, username='user2', password='user2', role='user', tenantid=41}
Listener invoked when adding user1
Added user1 to userCache using in thread_1
User{userid=3, username='user3', password='user3', role='user', tenantid=55}
Listener invoked when adding user3
Added user3 to userCache using in thread_1
User{userid=4, username='user4', password='user4', role='user', tenantid=9}
Added user4 to userCache using in thread_1
thread_1 will sleep during 12235 milliseconds
Added user2 to userCache using in thread_2
User{userid=5, username='user5', password='user5', role='user', tenantid=98}
Listener invoked when adding user5
Added user5 to userCache using in thread_2
User{userid=6, username='user6', password='user6', role='user', tenantid=85}
Listener invoked when adding user6
Added user6 to userCache using in thread_2
thread_2 will sleep during 10473 milliseconds
user1 exist using thread_2
thread_2 will sleep during 15808 milliseconds
user1 exist using thread_1
thread_1 will sleep during 25225 milliseconds
user2 exist using thread_2
thread_2 will sleep during 58012 milliseconds
user2 exist using thread_1
thread_1 will sleep during 13435 milliseconds
user3 exist using thread_1
thread_1 will sleep during 6692 milliseconds
user4 exist using thread_1
thread_1 will sleep during 25113 milliseconds
user5 exist using thread_1
thread_1 will sleep during 28972 milliseconds
user3 exist using thread_2
thread_2 will sleep during 58581 milliseconds
user6 exist using thread_1
user4 not exist using thread_2
thread_2 will sleep during 21540 milliseconds
user5 not exist using thread_2
thread_2 will sleep during 1090 milliseconds
user6 not exist using thread_2
Bye bye....

Building Cache Configuration using API:

Here is the way to manage cache using API.Below snippet will explain building cache configuration using api.

// building cache configuration
        CacheConfigurationBuilder<Integer,User> cacheConfigurationBuilder = CacheConfigurationBuilder.newCacheConfigurationBuilder();
        cacheConfigurationBuilder.withExpiry(new Expiry() {
            @Override
            public Duration getExpiryForCreation(Object key, Object value) {
                return new Duration(120, TimeUnit.SECONDS);
            }
            @Override
            public Duration getExpiryForAccess(Object key, Object value) {
                return new Duration(120, TimeUnit.SECONDS);
            }
            @Override
            public Duration getExpiryForUpdate(Object key, Object oldValue, Object newValue) {
                return null;
            }
        })
        .evictionVeto(new UserEvictionVeto())
        .usingEvictionPrioritizer(Eviction.Prioritizer.LFU)
        .withResourcePools(ResourcePoolsBuilder.newResourcePoolsBuilder().heap(200, EntryUnit.ENTRIES))
         // adding defaultSerializer config service to configuration
        .add(new DefaultSerializerConfiguration(CompactJavaSerializer.class, SerializerConfiguration.Type.KEY))
        .buildConfig(Integer.class, User.class);

        // building cache manager
        CacheManager cacheManager
                = CacheManagerBuilder.newCacheManagerBuilder()
                .withCache("userCache", cacheConfigurationBuilder.buildConfig(Integer.class, User.class))
                .build(false);
        cacheManager.init();
        Cache<Integer, User> preConfigured =
                cacheManager.getCache("userCache", Integer.class, User.class);
        User user1 = new User(1, "user1", "user1", "admin", 100);
        User user2 = new User(2, "user1", "user1", "student", 101);
        preConfigured.put(1, user1);
        preConfigured.put(2, user2);

        // asserting values from cache
        assertEquals(user1,preConfigured.get(1));
        assertEquals(user2,preConfigured.get(2));
        //removing cache from EhcacheManager
        cacheManager.removeCache("preConfigured");
        // Closing cache manager
        cacheManager.close();



You can download source from GitHub.




Getting started with Ehcache 2.X with a simple demo.

Ehcache is an open-source, standards-based cache for boosting performance, offloading your database, and simplifying scalability. As a robust, proven, and full-featured solution, it is today’s most widely used Java-based cache. You can use Ehcache as a general-purpose cache or a second-level cache for Hibernate.

Here let me explaing how to use Ehcache with a simple mutithreading program.Lets start with dependencies required,Below are the depdendecies required to use Ehcache.


        <dependency>
            <groupId>net.sf.ehcache</groupId>
            <artifactId>ehcache</artifactId>
            <version>2.10.0</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.5.6</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-jdk14</artifactId>
            <version>1.5.6</version>
        </dependency>


Configuration XML :
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="ehcache.xsd" updateCheck="true"
         monitoring="autodetect" dynamicConfig="true">

    <diskStore path="java.io.tmpdir"/>

    <cache name="cache1"
           maxEntriesLocalHeap="1000"
           maxEntriesLocalDisk="10000"
           eternal="false"
           diskSpoolBufferSizeMB="20"
           timeToIdleSeconds="60"
           timeToLiveSeconds="300"
           memoryStoreEvictionPolicy="LFU"
           transactionalMode="off">
        <persistence strategy="localTempSwap"/>
    </cache>

    <cache name="cache2"
           maxEntriesLocalHeap="1000"
           maxEntriesLocalDisk="10000"
           eternal="false"
           diskSpoolBufferSizeMB="20"
           timeToIdleSeconds="120"
           timeToLiveSeconds="600"
           memoryStoreEvictionPolicy="LFU"
           transactionalMode="off">
        <persistence strategy="localTempSwap"/>
    </cache>

</ehcache>



Let me brieflly explain about attributes of Cache tag

  1. maxEntriesLocalHeap : Maximum no of elements allowed in memory.
  2. maxEntriesLocalDisk : Once Heap is full,then element overflow to disk memory.So this is maximum no of elements allowed in Disk.
  3. eternal : Sets whether elements are eternal. If eternal,  timeouts are ignored and the element is never expired.
  4. diskSpoolBufferSizeMB : This is the size to allocate the DiskStore for a spool buffer. Writes are made
        to this area and then asynchronously written to disk. The default size is 30MB.
  5. timeToIdleSeconds : Element will expire if idle time reachs to timeToIdleSeconds(in seconds).
  6. timeToLiveSeconds : Element will expire if life of the element reachs to timeToIdleSeconds(in seconds).
  7. memoryStoreEvictionPolicy : Policy would be enforced upon reaching the maxEntriesLocalHeap limit. Default policy is Least Recently Used (specified as LRU). Other policies available - First In First Out (specified as FIFO) and Less Frequently Used (specified as LFU)
  8. transactionalMode :  To enable an ehcache as transactions, set the transactionalMode.
  9. diskStore : If heap memory is full,then elements overflow to disk.Diskstore is the path of disk directory.

There are many such attributes in xml configuration,please go through ehcache schema definition.


User Model Class :
public class User implements Serializable{

    private Integer userid;
    private String username;
    private String password;
    private String role;
    private Integer tenantid;

    public User(Integer userid, String username, String password, String role, Integer tenantid) {
        this.userid = userid;
        this.username = username;
        this.password = password;
        this.role = role;
        this.tenantid = tenantid;
    }

//setters & getters

}

CachedUserManager :

CachedUserManager will intract with cache and do CRUD operations on cache.

public class CachedUserManager<K extends Integer, V extends User> {

    private final Cache cache;

    public CachedUserManager(Cache cache) {
        this.cache = cache;
    }

    public void add(K k, V v) {
        cache.put(new Element(k, v));
    }

    public V getValue(K k) {
        return (V) cache.get(k).getObjectValue();
    }

    public boolean keyExist(K k) {
        return cache.get(k) == null ? false : true;
    }

    public void deleteElement(K k) {
        if (cache.get(k) != null) {
            cache.remove(k);
        }
    }

    public Cache getCache() {
        return cache;
    }
}

UserEhcacheDemo :

Here is the Demo code to add user objects into cache.This demo will explaing how to add User object to cache and making current thread to sleep, so that idle time of user objects reachs to timeToIdleSeconds(specified in xml) hence objects status will changed to expire and removed from cache.


public class UserEhcacheDemo {


    public static final String CACHE_1 = "cache1";
    public static final String CACHE_2 = "cache2";

    public static void main(String[] args) {

        CacheManager cacheManager = buildCacheManager();
        Cache cache1 = getCache1(cacheManager);
        Cache cache2 = getCache2(cacheManager);
        final CachedUserManager cachedUserManager1 = new CachedUserManager<Integer, User>(cache1);
        final CachedUserManager cachedUserManager2 = new CachedUserManager<Integer, User>(cache2);

        int noOfThreads = 2;
        ExecutorService execService = Executors.newFixedThreadPool(noOfThreads);
        execService.submit(new Runnable() {
            String threadName = "thread_1";
            @Override
            public void run() {
                //adding some users to cache1
                addUsersToCache(cachedUserManager1,threadName);

                //retrieve users from cache1
                Integer i = new Integer(1);
                while(i<5)
                {
                    //any random value between 1 to 45 sec
                    int sleepTime = getRandomSleepTime(1000, 45000);
                    System.out.println(threadName +" will sleep during "+sleepTime+" milliseconds");
                    try {
                        Thread.currentThread().sleep(sleepTime);
                    }catch (InterruptedException e)
                    {
                        //do nothing
                    }
                    boolean exist = cachedUserManager1.keyExist(i);
                    System.out.println("user"+i+ (exist?" exist":" not exist")+ " in cache1 with "+threadName);
                    i++;
                }


            }
        });
        execService.submit(new Runnable() {
            String threadName = "thread_2";
            @Override
            public void run() {
                //adding some users to cache2
                addUsersToCache(cachedUserManager2,threadName);

                //retrieve users from cache1
                Integer i = new Integer(1);
                while(i<5)
                {
                    //any random value between 30 to 60 sec
                    int sleepTime = getRandomSleepTime(30000, 60000);
                    System.out.println(threadName +" will sleep during "+sleepTime+" milliseconds");
                    try {
                        Thread.currentThread().sleep(sleepTime);
                    }catch (InterruptedException e)
                    {
                        //do nothing
                    }
                    boolean exist = cachedUserManager2.keyExist(i);
                    System.out.println("user"+i+ (exist?" exist ":" not exist ")+ "in cache2 with "+threadName);
                    i++;
                }
            }
        });

    }

    public static Cache getCache1(CacheManager cacheManager) {
        return cacheManager.getCache(CACHE_1);
    }

    public static Cache getCache2(CacheManager cacheManager) {
        return cacheManager.getCache(CACHE_2);
    }

    public static CacheManager buildCacheManager() {
        InputStream is = UserEhcacheDemo.class.getClassLoader().getResourceAsStream("com/ehcache/userCache.xml");
        return CacheManager.create(is);
    }

    private static void addUsersToCache(CachedUserManager cachedUserManager,String threadName) {
        Integer i = new Integer(1);
        while(i<5){
            cachedUserManager.add(i, new User(i, "user" + i, "password" + i, "role" + i, i));
            System.out.println("Added user"+ i + " to "+ cachedUserManager.getCache().getName() + " using " + threadName);
            i++;
        }
    }

    private static int getRandomSleepTime(int min, int max){
        return min + (int)(Math.random() * ((max - min) + 1));
    }

}


Above program will have mutiple outputs,Here is one among them

Added user1 to cache2 using thread_2
Added user2 to cache2 using thread_2
Added user3 to cache2 using thread_2
Added user4 to cache2 using thread_2
thread_2 will sleep during 37461 milliseconds
Added user1 to cache1 using thread_1
Added user2 to cache1 using thread_1
Added user3 to cache1 using thread_1
Added user4 to cache1 using thread_1
thread_1 will sleep during 11195 milliseconds
user1 exist in cache1 with thread_1
thread_1 will sleep during 12607 milliseconds
user2 exist in cache1 with thread_1
thread_1 will sleep during 16771 milliseconds
user1 exist in cache2 with thread_2
thread_2 will sleep during 44240 milliseconds
user3 exist in cache1 with thread_1
thread_1 will sleep during 10718 milliseconds
user4 exist in cache1 with thread_1
user2 exist in cache2 with thread_2
thread_2 will sleep during 56851 milliseconds
user3 not exist in cache2 with thread_2
thread_2 will sleep during 41211 milliseconds
user4 not exist in cache2 with thread_2



In the Demo program,we have two threads adding 4 users to respective cache.After adding users,trying to retrieving users from cache.While retrieving, threads to going to sleep.Sleep time is randomly calculated as mentioned in the program.If you remember we kept idle time to 1 and 2 mins in respective cache configuration.So if thread sleep for more then 1 min with out reading elements then such elements will expire and removed from cache.
In the above output, users like user4 not exist in cache1 and user3,user4 not exists in cache2.It mean idle time reached for these users,so expired.

You can download source from GitHub.

Creating Proxies Dynamically Using CGLIB Library with examples

CGLIB is a bytecode generation framework,there are many such frameworks which do same job.But CGLIB is high-level framework that would dynamically change classes providing its proxy and substituting the functionality of some methods.

Even JDK dynamic proxies can do same,but there are some cons in JDK proxies.JDK proxies will only work if your class is implemented from interface/s.Where as CGLIB does not have such restriction.It will create subclass(proxy) to any class.

CGLIB is a powerful, high performance code generation library, that relies on low-level
ASM framework.It is widely used behind the scenes in proxy-based Aspect Oriented Programming (AOP) frameworks, such as Spring AOP and dynaop, to provide method interceptions. Hibernate, the most popular object-relational mapping tool, also uses the CGLIB library to proxy single-ended (many-to-one and one-to-one) associations (not lazy fetching for collections, which is implemented using a different mechanism). EasyMock and jMock are libraries for testing Java code using mock objects. Both of them use the CGLIB library to create mock objects for classes that do not have interfaces.


Here I will explain creating proxies in four ways using CGLIB library.Let me take a simple java class and create proxy for this class.
public class JobsManager {
private static List<String> jobs = new ArrayList<String>();
      static {
            jobs.add("job1");
            jobs.add("job2");
            jobs.add("job3");
      }
       public List<String> getAllJobs() {
            return jobs;
      }
      public int getCount()
            return jobs.size();
      }
       public boolean createJob(String name) {
            return jobs.add(name);
      }
}
In all below example,we will create proxy for this JobsManager and do method calls on proxy instance.

1) Create proxy using callbackhandler InvocationHandler : 

public class JobsInvocationHandlerDemo {
    public static void main(final String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(JobsManager.class);
        enhancer.setCallback(new InvocationHandler() {
            @Override
            public Object invoke(Object obj, Method method, Object[] args) throws Throwable {
                // redirecting all object class method calls to its super
                if (method.getDeclaringClass().equals(Object.class)) {
                    return NoOp.INSTANCE;
                }
                // returning static jobs list
                if (method.getName().equals("getAllJobs")) {
                    return Arrays.asList(new String[]{"job5", "job6", "job7"});
                }
                // returning static jobs count
                if (method.getName().equals("getCount")) {
                    return 555;
                }
                // which will create end less loop, you should be more care full in using invocation handler.
                //if(method.getName().equals("createJob"))
                //return method.invoke(obj,args);
                return null;
            }
        });
        // jobsManager is proxified class object
        JobsManager jobsManager = (JobsManager) enhancer.create();
        // jobs list will not equal with proxy method call
        Assert.assertNotEquals(new JobsManager().getAllJobs().get(0), jobsManager.getAllJobs().get(0));
        // jobs count will not equal with proxy method call
        Assert.assertNotEquals(new JobsManager().getCount(), jobsManager.getCount());
         //which will go end less loop if you uncomment above method.invoke
        //Assert.assertEquals(true, jobsManager.createJob("job4"));
    }
}
All the JobsManager proxy method calls will go though Invocationhanler, here you can write your own code or redirect.
But there is a limitation in Invocationhanler,if any method call dispatchs to its super class then it will result in an endless loop.

2) Create proxy using callbackhandler MethodInterceptor :

public class JobsMethodInterceptorDemo {
public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(JobsManager.class);
        enhancer.setCallback(new MethodInterceptor() {
            @Override
            public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                // redirecting all object class method calls to its super
                if (method.getDeclaringClass().equals(Object.class)) {
                    return NoOp.INSTANCE;
                }
                // returning some static jobs list
                if (method.getName().equals("getAllJobs")) {
                    return Arrays.asList(new String[]{"job5", "job6", "job7"});
                }
                // returning some static jobs count
                if (method.getName().equals("getCount")) {
                    return 555;
                }
                // redirecting it its super class
                if (method.getName().equals("createJob")) {
                    return methodProxy.invokeSuper(obj, args);
                }
                // NoOp Instance
                return NoOp.INSTANCE;
            }
        });
        // jobsManager is proxified class object
        JobsManager jobsManager = (JobsManager) enhancer.create();
        // jobs list will not equal with proxy method call
        Assert.assertNotEquals(new JobsManager().getAllJobs().get(0), jobsManager.getAllJobs().get(0));
        // jobs count will not equal with proxy method call
        Assert.assertNotEquals(new JobsManager().getCount(), jobsManager.getCount());
        // here both should be true.
        Assert.assertEquals(true, jobsManager.createJob("job4"));
    }
}
The MethodInterceptor allows full control over the intercepted method and offers some utilities for calling the method of the enhanced class.MethodInterceptor is the callback for all methods of a proxy, method invocations on the proxy are routed to this method before invoking the methods on the original object.

3)Create proxy using callbackhandler MethodInterceptor and CallBackFilter :

public class JobsInterceptorWithCallBackFilter {
    public static void main(final String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(JobsManager.class);
        enhancer.setCallbackFilter(new CallbackFilter() {
            @Override
            public int accept(Method method) {
                if (method.getDeclaringClass().equals(Object.class)) {
                    return 0;
                }
                if (method.getName().equals("getAllJobs")) {
                    return 1;
                }
                if (method.getName().equals("getCount") || method.getName().equals("createJob")) {
                    return 2;
                }
                return 0;
            }
        });
        enhancer.setCallbacks(new Callback[]{NoOp.INSTANCE, new FixedValue() {
            @Override
            public Object loadObject() throws Exception {
                return Arrays.asList(new String[]{"job5", "job6", "job7"});
            }
        }, new MethodInterceptor() {
            @Override
            public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                return methodProxy.invokeSuper(obj, args);
            }
        }});
        // jobsManager is proxified class object
        JobsManager jobsManager = (JobsManager) enhancer.create();
        // jobs list will not equal with proxy method call
        Assert.assertNotEquals(new JobsManager().getAllJobs().get(0), jobsManager.getAllJobs().get(0));
        // jobs count will be equal with proxy method call
        Assert.assertEquals(new JobsManager().getCount(), jobsManager.getCount());
        // here both should be true.
        Assert.assertEquals(true, jobsManager.createJob("job4"));
    }
}
If you want to use multiple callback filters based on some condition then use CallbackFilter. CallbackFilter is selectively apply callbacks on the methods. This feature is not available in the JDK dynamic proxy.
4) Create proxy using callbackhandler MethodInterceptor and CallBackHelper : 

public class JobsInterceptorWithCallBackHelper {
    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(JobsManager.class);
        CallbackHelper callbackHelper = new CallbackHelper(JobsManager.class, new Class[0]) {
            @Override
            protected Object getCallback(Method method) {
                if (method.getDeclaringClass().equals(Object.class)) {
                    return NoOp.INSTANCE;
                }
                if (method.getName().equals("getAllJobs")) {
                    return new FixedValue() {
                        @Override
                        public Object loadObject() throws Exception {
                            return Arrays.asList(new String[]{"job5", "job6", "job7"});
                        }
                    };
                }
                if (method.getName().equals("getCount") || method.getName().equals("createJob")) {
                    return new MethodInterceptor() {
                        @Override
                        public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                            return methodProxy.invokeSuper(obj, args);
                        }
                    };
                }
                return NoOp.INSTANCE;
            }
        };
        enhancer.setCallbackFilter(callbackHelper);
        enhancer.setCallbacks(callbackHelper.getCallbacks());
        // jobsManager is proxified class object
        JobsManager jobsManager = (JobsManager) enhancer.create();
        // jobs list will not equal with proxy method call
        Assert.assertNotEquals(new JobsManager().getAllJobs().get(0), jobsManager.getAllJobs().get(0));
        // jobs count will be equal with proxy method call
        Assert.assertEquals(new JobsManager().getCount(), jobsManager.getCount());
        // here both should be true.
        Assert.assertEquals(true, jobsManager.createJob("job4"));
    }
}

CallBackHelper is one of the implementation of CallBackFilter provided by CGLIB.

There are other callbacks which are introduced for simplicity and performance :


  • FixedValue : It is useful to force a particular method to return a fixed value for performance reasons.
  • NoOp  : It delegates method invocations directly to the default implementations in the super class.
  • LazyLoader : It is useful when the real object needs to be lazily loaded. Once the real object is loaded, it is used for every future method call to the proxy instance.
  • Dispatcher : It has the same signatures as LazyLoader, but the loadObject method is always called when a proxy method is invoked.
  • ProxyRefDispatcher : It is the same as Dispatcher, but it allows the proxy object to be passed in as an argument of the loadObject method.


You can download source @ GitHub.