DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Because the DevOps movement has redefined engineering responsibilities, SREs now have to become stewards of observability strategy.

Apache Cassandra combines the benefits of major NoSQL databases to support data management needs not covered by traditional RDBMS vendors.

The software you build is only as secure as the code that powers it. Learn how malicious code creeps into your software supply chain.

Generative AI has transformed nearly every industry. How can you leverage GenAI to improve your productivity and efficiency?

Related

  • Writing DTOs With Java8, Lombok, and Java14+
  • Redefining Java Object Equality
  • Addressing Memory Issues and Optimizing Code for Efficiency: Glide Case
  • Singleton: 6 Ways To Write and Use in Java Programming

Trending

  • SaaS in an Enterprise - An Implementation Roadmap
  • Go 1.24+ Native FIPS Support for Easier Compliance
  • ITBench, Part 1: Next-Gen Benchmarking for IT Automation Evaluation
  • The Perfection Trap: Rethinking Parkinson's Law for Modern Engineering Teams
  1. DZone
  2. Coding
  3. Languages
  4. Java Dynamic Proxy: What is a Proxy and How can We Use It

Java Dynamic Proxy: What is a Proxy and How can We Use It

Learn all about Java dynamic proxies: what they are, when to use, how and when to use in code.

By 
Peter Verhas user avatar
Peter Verhas
DZone Core CORE ·
Feb. 08, 16 · Analysis
Likes (17)
Comment
Save
Tweet
Share
144.8K Views

Join the DZone community and get the full member experience.

Join For Free

What is a Proxy?

Proxy is a design pattern. We create and use proxy objects when we want to add or modify some functionality of an already existing class. The proxy object is used instead of the original one. Usually, the proxy objects have the same methods as the original one and in Java proxy classes usually extend the original class. The proxy has a handle to the original object and can call the method on that.

This way proxy classes can implement many things in a convenient way:

  • logging when a method starts and stops
  • perform extra checks on arguments
  • mocking the behavior of the original class
  • implement lazy access to costly resources

Without modifying the original code of the class. (The above list is not extensive, it only list some  examples).

In practical applications, the proxy class does not directly implement the functionality. Following the single responsibility principle, the proxy class does only proxying and the actual behavior modification is implemented in handlers. When the proxy object is invoked instead of the original object, the proxy decides if it has to invoke the original method or some handler. The handler may do its task and may also call the original method.

Even though the proxy pattern does not only apply to situations when the proxy object and proxy class is created during run-time, this is an especially interesting topic in Java. In this article, I will focus on these proxies.

This is an advanced topic because it requires the use of the reflection class, or bytecode manipulation or compiling Java code generated dynamically. Or all of these. To have a new class not available as a bytecode yet during run-time will need the generation of the bytecode, and a class loader that loads the bytecode. To create the bytecode, you can use cglib or bytebuddy or the built-in Java compiler.

When we think about the proxy classes and the handlers they invoke, we can understand why the separation of responsibilities, in this case, is important. The proxy class is generated during run-time, but the handler invoked by the proxy class can be coded in the normal source code and compiled along the code of the whole program (compile time).

How Can We Use This In Our Code?

The easiest way to do this is to use the java.lang.reflect.Proxy class, which is part of the JDK. That class can create a proxy class or directly an instance of it. The use of the Java built-in proxy is easy. All you need to do is implement a java.lang.InvocationHandler , so that the proxy object can invoke it. The InvocationHandler interface is extremely simple. It contains only one method: invoke(). When invoke() is invoked, the arguments contain the original object, which is proxied, the method that was invoked (as a reflection Method object) and the object array of the original arguments. A sample code demonstrates the use:


package proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class JdkProxyDemo {

    interface If {
        void originalMethod(String s);
    }

    static class Original implements If {
        public void originalMethod(String s) {
            System.out.println(s);
        }
    }

    static class Handler implements InvocationHandler {
        private final If original;

        public Handler(If original) {
            this.original = original;
        }

        public Object invoke(Object proxy, Method method, Object[] args)
                throws IllegalAccessException, IllegalArgumentException,
                InvocationTargetException {
            System.out.println("BEFORE");
            method.invoke(original, args);
            System.out.println("AFTER");
            return null;
        }
    }

    public static void main(String[] args){
        Original original = new Original();
        Handler handler = new Handler(original);
        If f = (If) Proxy.newProxyInstance(If.class.getClassLoader(),
                new Class[] { If.class },
                handler);
        f.originalMethod("Hallo");
    }

}

If the handler wants to invoke the original method on the original object, it has to have access to it. This is not provided by the Java proxy implementation. You have to pass this argument to the handler instance yourself in your code. (Note that there is an object usually named proxy passed as an argument to the invocation handler. This is the proxy object that the Java reflection dynamically generate and not the object we want to proxy.) This way you are absolutely free to use a separate handler object for each original class or use some shared object that happens to know some way which original object to invoke if there is any method to invoke at all.

As a special case, you can create an invocation handler and a proxy of an interface that does not have any original object. Even more, it is not needed to have any class to implement the interface in the source code. The dynamically created proxy class will implement the interface.

What should you do if the class you want to proxy does not implement an interface? In that case, you have to use some other proxy implementation. We will look at that in a coming post.

Java (programming language) Object (computer science)

Published at DZone with permission of Peter Verhas, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Writing DTOs With Java8, Lombok, and Java14+
  • Redefining Java Object Equality
  • Addressing Memory Issues and Optimizing Code for Efficiency: Glide Case
  • Singleton: 6 Ways To Write and Use in Java Programming

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!