Java는 AOP 탄젠트 프로그래밍을 위한 인스턴스 자습서를 구현합니다.

10158 단어 JavaAOP
소개
모두가 알다시피 AOP는 Spring 프레임워크의 특색 있는 기능 중 하나입니다.횡단 관심사(cross cutting concerns)를 설정함으로써 AOP는 높은 확장성을 제공합니다.그럼 AOP는 Spring에서 어떻게 작동하나요?코어자바만 사용할 수 있지만 AOP 기술이 필요할 때 이 문제의 해답은 매우 관건적이다.뿐만 아니라 고급 기술직 면접에서도 이런 문제가 시험문제로 자주 등장한다.아니, 내 친구는 최근에 면접을 봤는데 이런 까다로운 질문을 받았다. 어떻게 스프링과 관련 라이브러리를 사용하지 않고 코어 자바만 사용하는 조건에서 AOP를 실현할 수 있느냐는 것이다.따라서 저는 본고에서 개요를 제공하여 여러분들이 코어 자바만으로 어떻게 하나의 AOP를 실현하는지 이해하도록 돕겠습니다(물론 이런 AOP는 기능적으로 어느 정도 한계가 있습니다).주의, 본고는 스프링 AOP와 자바 AOP에 대한 비교 연구가 아니라 코어 자바에서 고유한 디자인 모델을 빌려 AOP를 실현하는 강좌에 관한 것이다.
독자들은 AOP가 무엇인지 알고 스프링 프레임워크에서 어떻게 사용하는지 알고 있기 때문에 본고는 스프링을 사용하지 않는 전제에서 AOP를 실현하는 방법에만 착안한다.우선, 스프링은 JDKproxy와 CGlib 두 가지 기술을 빌려 AOP를 실현했다는 것을 알아야 한다.JDK dynamic proxy는 hook의 방법을 제공하고 지정한 조작을 실행하는 유연한 방식을 제공하지만, 조작을 실행할 때 반드시 관련 인터페이스와 이 인터페이스의 실현 클래스를 제공해야 한다.실천을 통해 진정한 지식을 얻고, 우리 하나의 사례를 통해 이 문장을 이해합시다!현재 수학 연산을 완성하는 데 사용되는 계산기 프로그램이 있다.다음 제법 기능을 고려해 보겠습니다. 이때 문제는 코어 프레임워크가 제법을 실현하는 코드를 갖추고 있다면, 코드가 실행될 때 납치(highjack)를 하고 추가 검사를 수행할 수 있습니까?답은 긍정적이다. 나는 아래에서 제공한 코드 단편으로 이 점을 증명할 것이다.먼저 기본 인터페이스의 코드를 살펴보겠습니다.

public interface Calculator {
  public int calculate( int a , int b);
}
이 인터페이스 구현 클래스의 코드는 다음과 같습니다.

public class CalculatorImpl implements Calculator {
  @Override
  public int calculate(int a, int b) {
    return a/b;
  }
}
가령 우리가 이 위의 코드를 고칠 수도 없고 핵심 라이브러리에 대해 어떠한 변경도 할 수 없다면 어떻게 해야만 검사 기능을 완벽하게 실현할 수 있습니까?차라리 JDK dynamic proxy의 기능을 시험해 보세요.

public class SomeHandler implements InvocationHandler {
 
// Code omitted for simplicity…..
 
  @Override
  public Object invoke(Object proxy, Method method, Object[] params) throws Throwable {
// Your complex business validation and logic
    Object result = method.invoke(targetObject ,params);
    return result;
  }
 
}
테스트 클래스를 통해 JDK dynamic proxy로 이루어진 검사 기능의 효과가 어떠한지 살펴봅시다.

public static void main(String[] args) {
    CalculatorImpl calcImpl = new CalculatorImpl();
    Calculator proxied = (Calculator)ProxyFactory.getProxy (Calculator.class, calcImpl, 
        new SomeHandler(calcImpl));
    int result = proxied.calculate(20, 10);
    System.out.println("FInal Result :::" + result);
  }
결과에서 알 수 있듯이 기능이 강한 Invocation Handler 인터페이스를 간단하게 실현하면 우리는 hooking implementation을 얻을 수 있다.JDK 문서의 설명에 따르면 InvocationHandler 인터페이스는 프록시 인스턴스(proxy instance)를 통해 하나의 방법으로 호출됩니다.
이제 우리는 InvocationHandler의 invoke () 방법이 문제를 해결하는 데 도움을 줄 수 있다는 것을 알고 있다.그렇다면 어떻게 해야만 방법이 집행되는 전후에 조작을 집행할 수 있습니까?좀 더 구체적으로 말하자면, 우리는 여러 개의 aop(before, after, around)을 추가해서 훅을 할 수 있습니까?답안 역시 긍정적이다.다음 절차에 따라 간단한 코드 템플릿을 만들면 이러한 요구를 충족시킬 수 있습니다.
  • aop을 목표 대상에 적용하는 추상적인 클래스를 만듭니다..
  • BeforeHandler와 AfterHandler라는 두 개의 aop을 만듭니다.전자는 방법이 집행되기 전에 일하고 후자는 방법이 집행된 후에 일한다
  • 모든 aophandler와 목표 대상을 매개 변수로 전송하기만 하면 훅을 만들 수 있는 프록시 클래스를 만듭니다..
  • 당신의 업무 논리나 횡단 관심사에 가입하세요..
  • 마지막으로 관련 매개 변수를 전송하여 프록시 대상 (proxy object) 을 만듭니다..
  • 두 가지 AOP 구현 방법:
    1, JDK가 제공하는 동적 에이전트 구현
    인터페이스
    
    public interface UserBean 
    { 
      void getUser(); 
      void addUser(); 
      void updateUser(); 
      void deleteUser(); 
    } 
    
    원시 실현 클래스
    
    public class UserBeanImpl implements UserBean 
    { 
      private String user = null; 
      public UserBeanImpl() 
      {     
      }   
      public UserBeanImpl(String user) 
      { 
        this.user = user; 
      }   
      public String getUserName() 
      { 
        return user; 
      }   
      public void getUser() 
      { 
        System.out.println("this is getUser() method!"); 
      } 
     
      public void setUser(String user) 
      { 
        this.user = user; 
        System.out.println("this is setUser() method!"); 
      } 
      public void addUser() 
      { 
        System.out.println("this is addUser() method!"); 
      } 
       
      public void updateUser() 
      { 
        System.out.println("this is updateUser() method!"); 
      }   
      public void deleteUser() 
      { 
        System.out.println("this is deleteUser() method!");  
      }     
    } 
    
    대리류
    
    import java.lang.reflect.InvocationHandler; 
    import java.lang.reflect.Method; 
    import java.lang.reflect.Proxy; 
    import com.cignacmc.finance.bean.UserBeanImpl; 
     
    public class UserBeanProxy implements InvocationHandler 
    { 
      private Object targetObject; 
       
      public UserBeanProxy(Object targetObject) 
      { 
        this.targetObject = targetObject;     
      } 
       
      public Object invoke(Object proxy, Method method, Object[] args) throws Throwable 
      { 
        UserBeanImpl userBean = (UserBeanImpl) targetObject; 
        String userName = userBean.getUserName(); 
        Object result = null; 
         
        //  
        if(userName != null && !"".equals(userName)) 
        { 
          result = method.invoke(targetObject, args); 
        } 
         
        return result; 
      } 
    } 
    
     
    테스트 클래스
    
    import java.lang.reflect.Proxy; 
     
    import com.cignacmc.finance.bean.UserBean; 
    import com.cignacmc.finance.bean.UserBeanImpl; 
    import com.cignacmc.finance.proxy.UserBeanProxy; 
     
    public class ProxyExe 
    { 
      public static void main(String[] args) 
      { 
        System.out.println("Proved............."); 
        UserBeanImpl targetObject = new UserBeanImpl("Bob Liang");    
        UserBeanProxy proxy = new UserBeanProxy(targetObject); 
        //      
        UserBean object = (UserBean)Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),  
            targetObject.getClass().getInterfaces(), proxy); 
        object.addUser(); 
         
        System.out.println("NO Proved............."); 
        targetObject = new UserBeanImpl();    
        proxy = new UserBeanProxy(targetObject); 
        //      
        object = (UserBean)Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),  
            targetObject.getClass().getInterfaces(), proxy); 
        object.addUser(); 
             
      } 
    } 
    
     
    출력:
    
    Proved............. 
    this is addUser() method! 
    NO Proved............. 
    
     
    위의 예에서 호출 방법addUser () 를 성공적으로 차단하고 그에 상응하는 처리를 할 수 있다
     
    2, cglib를 통해 프록시 클래스 만들기
    좋은 점은 우리의 목표 대상이 인터페이스를 실현하도록 요구하지 않는다는 것이다
    원시류
    
    public class ClientBean 
    { 
      private String name = null; 
     
      public ClientBean() 
      { 
     
      } 
     
      public ClientBean(String name) 
      { 
        this.name = name; 
      } 
     
      public void addClient() 
      { 
        System.out.println("this is addClient() method!"); 
      } 
     
      public void deleteClient() 
      { 
        System.out.println("this is deleteClient() method!"); 
      } 
     
      public void getClient() 
      { 
        System.out.println("this is getClient() method!"); 
      } 
     
      public void updateClient() 
      { 
        System.out.println("this is updateClient() method!"); 
      } 
     
      public String getClientName() 
      { 
        return name; 
      } 
     
      public void setClientName(String name) 
      { 
        this.name = name; 
      } 
    } 
    
    대리류
    
    import java.lang.reflect.Method; 
     
    import com.cignacmc.finance.bean.ClientBean; 
     
    import net.sf.cglib.proxy.Enhancer; 
    import net.sf.cglib.proxy.MethodInterceptor; 
    import net.sf.cglib.proxy.MethodProxy; 
     
    public class CGLibProxy implements MethodInterceptor 
    { 
      private Object targetObject; 
       
      public Object createProxyObject(Object targetObject) 
      { 
        this.targetObject = targetObject; 
        Enhancer enhancer = new Enhancer(); 
        enhancer.setSuperclass(this.targetObject.getClass()); 
        enhancer.setCallback(this); 
        return enhancer.create(); 
      } 
       
      public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable 
      { 
        ClientBean clientBean = (ClientBean)targetObject; 
        String userName = clientBean.getClientName(); 
        Object result = null; 
         
        if(userName != null && !"".equals(userName)) 
        { 
          result = method.invoke(targetObject, args); 
        } 
        return result; 
      } 
    } 
    
    테스트 클래스
    
    import java.lang.reflect.Proxy; 
     
    import com.cignacmc.finance.bean.ClientBean; 
    import com.cignacmc.finance.bean.UserBean; 
    import com.cignacmc.finance.bean.UserBeanImpl; 
    import com.cignacmc.finance.proxy.CGLibProxy; 
    import com.cignacmc.finance.proxy.UserBeanProxy; 
     
    public class ProxyExe 
    { 
      public static void main(String[] args) 
      {   
        System.out.println(".............CGLIB Proxy...................."); 
        System.out.println("Proved...................."); 
        CGLibProxy cproxy = new CGLibProxy(); 
        ClientBean clientBean = (ClientBean)cproxy.createProxyObject(new ClientBean("Bob Liang")); 
        clientBean.addClient(); 
         
        System.out.println("NO Proved...................."); 
        cproxy = new CGLibProxy(); 
        clientBean = (ClientBean)cproxy.createProxyObject(new ClientBean()); 
        clientBean.addClient(); 
             
      } 
    } 
    
     
    출력:
    
    .............CGLIB Proxy.................... 
    Proved.................... 
    this is addClient() method! 
    NO Proved.................... 

    좋은 웹페이지 즐겨찾기