Javaエージェントの3つの実装を浅くする


注意:本文のすべてのclassで使用するstatic修飾は主に1つのクラスでテストできるようにするためです.実際のプロジェクトではそうすべきではなく、classを分けるべきだ.文字の説明はそんなに多くないので、コードを見たほうが分かりやすいでしょう...
1.Javaエージェントの理解 は、単純に言えば、ソースコードを変更することなく、ターゲットオブジェクトに対する機能拡張を実現する である.使用シーン:メソッドの実行前後に実行時間を計算したり、ログを記録したりします.これらの機能の拡張は、元のコードを変更することなく実現される.
2.エージェントモードの実現
2.1静的エージェント
2.1.0メリットとデメリット
  • の利点:必要なメソッドに対してのみエージェントロジックを追加します.
  • 欠点:1.エージェントのたびにエージェントクラスを実装する必要があります.2.エージェントクラスは機能が固定されており、柔軟に変更できない.3.プロジェクトには多くのエージェントのコードがあり、ターゲットオブジェクトが変更された場合、エージェントクラスも変更に対応する必要があり、コードのメンテナンスに不利である.

  • 2.1.1実現方式一:継承エージェント(継承方式実現エージェント)
    public class StaticProxyByExtendTest {
    
        //    
        public static class UserServiceImpl {
            public void login(String username, String pwd) {
                System.out.println("Welcome " + username);
            }
        }
        
        //    
        public static class UserServiceImplProxy extends UserServiceImpl{
            public void login(String username, String pwd) {
                System.out.println("before.... ");//      
                super.login(username, pwd);//       
                System.out.println("after.... ");//      
            }
        }
    
        //  
        public static void main(String[] args) {
            UserServiceImpl ee = new UserServiceImplProxy();
            ee.login("Stephen", "123");
        }
    
    }

    2.1.2実装方式2:集約方式(同じインタフェースを実装することによって)
    public class StaticProxyByGroupTest {
    
        public interface UserService {
            public void login(String username, String pwd);
        }
        
        //    
        public static class UserServiceImpl implements UserService {
    
            @Override
            public void login(String username, String pwd) {
                System.out.println("Welcome " + username);
            }
            
        }
        
        //    
        public static class UserServiceImplProxy implements UserService {
    
            private UserService userService;
            
            public UserServiceImplProxy(UserService userService) {
                this.userService = userService;
            }
            
            @Override
            public void login(String username, String pwd) {
                System.out.println("before.... ");//      
                userService.login(username, pwd);//       
                System.out.println("after.... ");//      
            }
            
        }
        
        public static void main(String[] args) {
            UserService target = new UserServiceImpl();
            UserService tt = new UserServiceImplProxy(target);
            tt.login("Stephen", "123");
        }
    
    }

    集約方式を使用すると、他のエージェントオブジェクトを追加して、すでにエージェントされているオブジェクトに対して拡張エージェントを続行することもできます.
    2.2動的エージェント(JDKエージェント)
    JDKオリジナルダイナミックエージェントはJavaオリジナルサポートであり、外部依存は必要ありませんが、 のみでエージェントを行うことができます.
    2.2.0メリットとデメリット
  • の利点:動的エージェントのすべてのインタフェース.
  • の欠点:エージェントを実装するためにインタフェース方式を使用することに依存しなければならない.

  • 主な実装はJDKが持つProxyクラスを用いて実現する.
    newProxyInstance(ClassLoader loader, Class>[] interfaces, InvocationHandler h)

    Returns an instance of a proxy class for the specified interfaces that dispatches method invocations to the specified invocation handler.
    動的エージェントは,メソッドを逐一エージェントする必要がなく,すべてのインタフェースメソッドを反射サイクルすることによって,動的にエージェントロジックを加える.メソッドの名前を実行することで、現在のメソッドにエージェントが必要かどうかをフィルタすることもできます.
    2.2.1基本実装方式
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    public class DynamicProxyByJDKTest {
        
        public interface UserService {
            public void login(String username, String pwd);
        }
        
        //    
        public static class UserServiceImpl implements UserService {
    
            @Override
            public void login(String username, String pwd) {
                System.out.println("Welcome " + username);
            }
            
        }
        
        //    1
        public static class UserServiceImplProxy {
    
            private UserService userServiceProxy;
            
            public UserServiceImplProxy(UserService userService) {
            //  JDK      UserService     
                UserService proxy = (UserService) Proxy.newProxyInstance(
                        userService.getClass().getClassLoader(), //1.     
                        userService.getClass().getInterfaces(), // 2.          ,     
                        new InvocationHandler() { // 3.           
    
                            @Override
                            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                                System.out.println("before.... ");//      
                                Object returnValue = method.invoke(userService, args);
                                System.out.println("after.... ");//      
                                return returnValue;
                            }
                            
                        });
                
                this.userServiceProxy = proxy;
            }
    
            public UserService getProxy() {
                return this.userServiceProxy;
            }
            
        }
        
        //             
        @SuppressWarnings("unchecked")
        public static  T getJDKProxy(T t) {
            T proxy = (T) Proxy.newProxyInstance(
                    t.getClass().getClassLoader(), 
                    t.getClass().getInterfaces(), 
                    new InvocationHandler() {
    
                        @Override
                        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                            System.out.println("before.... ");//      
                            Object returnValue = method.invoke(t, args);
                            System.out.println("after.... ");//      
                            return returnValue;
                        }
                        
                    });
            
            return proxy;
        }
    
        public static void main(String[] args) {
            UserService target = new UserServiceImpl();
            //    1
            UserServiceImplProxy proxy = new UserServiceImplProxy(target);
            proxy.getProxy().login("Stephen", "123");
            
            //    
            UserService jdkProxy = getJDKProxy(target);
            jdkProxy.login("JDK Stephen", "123");
        }
    
    }

    2.2.2動的エージェントの最適化
    JDK Proxy動的エージェントのさらなる最適化:
  • 抽象出代理親
  • エージェントクラスは、独自のbeforeおよびafterメソッド
  • を実装する.
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    public class DynamicProxyByJDKTest2 {
        //    
        public interface UserService {
            public void login(String username, String pwd);
        }
        
        //    
        public static class UserServiceImpl implements UserService {
    
            @Override
            public void login(String username, String pwd) {
                System.out.println("Welcome " + username);
            }
            
        }
        
        //    
        public static class UserServiceImplProxy extends JDKProxy {
            
            public UserService userServiceProxy;
    
            public UserServiceImplProxy(UserService userService) {
                this.userServiceProxy = getJDKProxy(userService);
            }
            
            @Override
            protected void before(Method method) {
                System.out.println("before.... ");//      
            }
    
            @Override
            protected void after(Method method) {
                System.out.println("after.... ");//      
            }
    
        }
        
        //Common proxy object class
        public static abstract class JDKProxy {
            
            protected abstract void before(Method method);
            
            protected abstract void after(Method method);
            
            @SuppressWarnings("unchecked")
            protected  T getJDKProxy(T t) {
                T proxy = (T) Proxy.newProxyInstance(
                        t.getClass().getClassLoader(), 
                        t.getClass().getInterfaces(), 
                        new InvocationHandler() {
    
                            @Override
                            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                                before(method);//      
                                Object returnValue = method.invoke(t, args);
                                after(method);//      
                                return returnValue;
                            }
                            
                        });
                
                return proxy;
            }
        }
        
        public static void main(String[] args) {
            UserService target = new UserServiceImpl();
            //    
            UserServiceImplProxy proxy = new UserServiceImplProxy(target);
            proxy.userServiceProxy.login("Stephen", "123");
        }
    
    }

    2.3 CglibエージェントCGLIB(Code GenerationLibrary)はASMベースのバイトコード生成ライブラリであり、実行時にバイトコードを修正し、動的に生成することができます.CGLIB , , final 。
    2.3.0メリットとデメリット
  • 利点:Cglibエージェントはインタフェースに依存せず、JDKエージェントはインタフェース
  • に依存する.
  • 欠点:
  • SpringのAOPプログラミングでは、
  • コンテナに加入するターゲットオブジェクトに実装インタフェースがある場合、JDKエージェント
  • を使用する.
  • ターゲットオブジェクトがインタフェースを実装していない場合、Cglibエージェント
  • を使用する.
    2.3.1 spring-coreによるcglibエージェントの実装
    spring-coreを参照する必要があります.jarSpring Core » 5.1.8.RELEASE
    import java.lang.reflect.Method;
    
    import org.springframework.cglib.proxy.Enhancer;
    import org.springframework.cglib.proxy.MethodInterceptor;
    import org.springframework.cglib.proxy.MethodProxy;
    
    public class DynamicProxyBySpringCglibTest {
    
        //    
        public interface UserService {
            public void login(String username, String pwd);
        }
        
        //    
        public static class UserServiceImpl implements UserService {
    
            @Override
            public void login(String username, String pwd) {
                System.out.println("Welcome " + username);
            }
            
        }
        
        //    
        public static class ProxyFactory implements MethodInterceptor {
    
            private Object target;
            
            public ProxyFactory(Object target) {
                this.target = target;
            }
            
             public Object getProxyInstance(){
                 //1.    Enhancer           、           
                 Enhancer en = new Enhancer();
                 //2.    
                 en.setSuperclass(target.getClass());
                 //3.      
                 en.setCallback(this);
                 //4.    (    )
                 return en.create();
             }
            
            @Override
            public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
                System.out.println("before.... ");//      
                Object returnValue = method.invoke(target, args);
                System.out.println("after.... ");//      
                return returnValue;
            }
    
        }
        
        public static void main(String[] args) throws Exception {
            UserService target = new UserServiceImpl();
            UserService proxy = (UserService) new ProxyFactory(target).getProxyInstance();
            proxy.login("Stephen", "123");
        }
    
    }

    2.3.1 spring-coreによるcglibエージェントの実装(バージョンの最適化)
    主な最適化点:
  • 抽象共通ProxyFactoryクラス
  • を抽出
  • 特定のエージェントクラスの実装はProxyFactory
  • から継承される.
    import java.lang.reflect.Method;
    
    import org.springframework.cglib.proxy.Enhancer;
    import org.springframework.cglib.proxy.MethodInterceptor;
    import org.springframework.cglib.proxy.MethodProxy;
    
    public class DynamicProxyBySpringCglibTest1 {
    
        //    
        public interface UserService {
            public void login(String username, String pwd);
        }
        
        //    
        public static class UserServiceImpl implements UserService {
    
            @Override
            public void login(String username, String pwd) {
                System.out.println("Welcome " + username);
            }
            
        }
        
        //Common    
        public static abstract class ProxyFactory implements MethodInterceptor {
    
            private Object target;
            
            public ProxyFactory(Object target) {
                this.target = target;
            }
            
            public Object getProxyInstance(){
                 //1.   
                 Enhancer en = new Enhancer();
                 //2.    
                 en.setSuperclass(target.getClass());
                 //3.      
                 en.setCallback(this);
                 //4.    (    )
                 return en.create();
             }
             
            protected abstract void before(Method method);
                
            protected abstract void after(Method method);
            
            @Override
            public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
                before(method);
                Object returnValue = method.invoke(target, args);
                after(method);
                return returnValue;
            }
    
        }
        
        //      
        public static class UserServiceProxy extends ProxyFactory {
    
            public UserServiceProxy(Object target) {
                super(target);
            }
    
            @Override
            protected void before(Method method) {
                System.out.println("before.... " + method.getName());//      
            }
    
            @Override
            protected void after(Method method) {
                System.out.println("after.... " + method.getName());//      
            }
            
        }
        
        public static void main(String[] args) throws Exception {
            UserService target = new UserServiceImpl();
            UserService proxy = (UserService) new UserServiceProxy(target).getProxyInstance();
            proxy.login("Stephen", "123");
        }
    
    }

    3.Refs
  • API java.lang.reflect.Proxy
  • Spring Core » 5.1.8.RELEASE
  • javaの3つのエージェントモード
  • を理解する
  • javaエージェント
  • Javaエージェントと動的エージェントメカニズムの分析と応用
  • Java ProxyとCGLIBダイナミックエージェント原理