소개하다
우리 모두가 알고 있듯이 AOP (섹션 지향 프로그래밍)는 Spring 프레임 워크의 기능 중 하나입니다. AOP는 교차 절단 문제를 설정하여 매우 높은 확장 성을 제공합니다. 그렇다면 AOP는 봄에 어떻게 작동합니까? Core Java 만 사용할 수는 있지만 AOP 기술이 필요할 때이 질문에 대한 답은 매우 중요합니다. 뿐만 아니라 고급 기술 위치에 대한 인터뷰에서 그러한 질문은 종종 테스트 질문으로 나타납니다. 내 친구는 최근 인터뷰에 참석했으며 어려운 질문을 받았습니다. Spring 및 관련 라이브러리를 사용하지 않고 AOP를 구현하는 방법과 핵심 Java 만 있습니다. 따라서 코어 Java를 사용하여 AOP를 구현하는 방법을 이해하는 데 도움이되는이 기사에서 개요를 제공 할 것입니다 (물론 AOP에는 특정 기능 제한이 있습니다). 이 기사는 Spring AOP 및 Java AOP에 대한 비교 연구가 아니라 Core Java의 고유 한 설계 패턴을 사용하여 AOP 구현에 대한 튜토리얼입니다.
독자들은 이미 AOP가 무엇인지, 스프링 프레임 워크에서 사용하는 방법을 이미 알고 있다고 생각 하므로이 기사는 Spring을 사용하지 않고 AOP를 구현하는 방법에만 초점을 맞추고 있습니다. 우선, Spring은 JDK Proxy와 CGLIB의 두 가지 기술을 사용하여 AOP를 구현한다는 것을 알아야합니다. JDK Dynamic Proxy는 메소드를 연결하고 지정된 작업을 수행하는 유연한 방법을 제공하지만 작업을 수행 할 때 제한이 있어야합니다. 관련 인터페이스와 인터페이스의 구현 클래스가 먼저 제공되어야합니다. 진정한 지식을 만들기 위해 연습하고, 사건을 통해이 문장을 이해합시다! 이제 수학 작업을 수행하기위한 계산기 프로그램이 있습니다. 디비전 기능을 고려해 봅시다. 이 시점의 질문은 다음과 같습니다. 핵심 프레임 워크에 이미 부서를 구현할 코드가 있다면 코드를 실행할 때이를 납치하고 추가 검증을 수행 할 수 있습니까? 대답은 예이며, 아래에 제공된 코드 스 니펫으로 이것을 증명할 것입니다. 먼저 기본 인터페이스의 코드를 살펴 보겠습니다.
공개 인터페이스 계산기 {public int calculate (int a, int b);}이 인터페이스 구현 클래스의 코드는 다음과 같습니다.
공개 클래스 계산기 impl은 계산기를 구현합니다 {@override public int calculate (int a, int b) {return a/b; }}위의 코드를 복구 할 수 없거나 핵심 라이브러리를 변경할 수 없다고 가정하면 어떻게 확인 기능을 완벽하게 구현할 수 있습니까? JDK 동적 프록시 함수를 시도해보십시오.
공개 클래스의 일부 핸들러는 invocationHandler를 구현 {// 단순성을 위해 생략 된 코드… .. @Override public object invoke (개체 프록시, 메소드 메소드, 개체 [] 매개 변수) 던질 가능 {// 복잡한 비즈니스 유효성 검사 및 논리 객체 결과 = method.invoke (targetObject, params); 반환 결과; }}JDK Dynamic Proxy에 의해 구현 된 검증 기능이 테스트 클래스를 통해 어떻게 작동하는지 살펴 보겠습니다.
public static void main (String [] args) {calculatorimpl commimpl = new CalculatorImpl (); 계산기 proxied = (계산기) proxyfactory.getProxy (calculator.class, calcimpl, new someHandler (calcimpl)); int result = proxied.calculate (20, 10); System.out.println ( "최종 결과 :::" + 결과); }결과를 통해 강력한 InvocationHandler 인터페이스를 구현함으로써 Hooking 구현을 얻을 수 있음을 알 수 있습니다. JDK 문서에 따르면 InvocationHandler 인터페이스는 프록시 인스턴스를 사용하여 메소드 호출을 처리합니다.
이제 invoctionhandler의 invoke () 메소드가 문제를 해결하는 데 도움이 될 수 있음을 알고 있습니다. 새로운 문제를 해결하겠습니다. 메소드 실행 전후 작업을 수행 할 수있는 방법은 무엇입니까? 보다 구체적으로 말하면, 여러 AOP (이전, 후, 주변)를 추가하여 메소드를 연결할 수 있습니까 (번역기 주 : 원본 텍스트는 여러 AOP를 추가하지만 핸들러가 측면으로 작용한다고 생각합니까? 대답도 그렇습니다. 아래 단계를 따라 간소화 된 코드 템플릿을 작성 하여이 요구 사항을 충족하십시오.
AOP를 구현하는 두 가지 방법 :
1. JDK가 제공하는 동적 프록시 구현
인터페이스
공개 인터페이스 userBean {void getUser (); void adduser (); void updateUser (); void deleteuser (); } 원래 구현 클래스
공개 클래스 userBeanImpl은 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 () 메소드!"); } public void setUser (문자열 사용자) {this.user = user; System.out.println ( "이것은 setUser () 메소드입니다!"); } public void addUser () {System.out.println ( "this is addUser () 메소드!"); } public void updateUser () {system.out.println ( "this is updateUser () 메소드!"); } public void deleteuser () {System.out.println ( "this is deleteuser () 메소드!"); }} 에이전트 클래스
import java.lang.reflect.invocationHandler; import java.lang.reflect.method; java.lang.reflect.proxy import; com.cignacmc.finance.bean.userbeanimpl 가져 오기; 공개 클래스 userBeanProxy는 invocationHandler {private object targetObject; public userBeanProxy (Object TargetObject) {this.targetObject = targetObject; } public object invoke (개체 프록시, 메소드 메소드, 개체 [] args) 던질 가능 {userBeanImpl userBean = (userBeanImpl) targetObject; 문자열 username = userBean.getUserName (); 객체 결과 = null; // 허가 판단 if (username! = null &&! " } 반환 결과; }}
테스트 클래스
java.lang.reflect.proxy import; com.cignacmc.finance.bean.userbean import; com.cignacmc.finance.bean.userbeanimpl 가져 오기; com.cignacmc.finance.proxy.userbeanproxy 가져 오기; public class proxyexe {public static void main (String [] args) {System.out.println ( "증명 ........."); userBeanImpl targetObject = 새로운 userBeanImpl ( "Bob Liang"); userBeanProxy proxy = 새로운 userBeanProxy (TargetObject); // 프록시 객체 생성 userBean 객체 = (userBean) proxy.newProxyInstance (targetObject.getClass (). getClassLoader (), targetObject.getClass (). getInterfaces (), proxy); object.adduser (); System.out.println ( "입증되지 않았다 ............"); targetObject = 새로운 userBeanImpl (); 프록시 = 새로운 userBeanProxy (TargetObject); // 프록시 객체 생성 객체를 생성합니다. object.adduser (); }}
산출:
증명 ............ 이것은 AddUser () 메소드입니다! 증명되지 않았습니다 ..........
위의 예에서, 호출 된 메소드 addUser ()는 그에 따라 성공적으로 가로 채고 처리 될 수있다.
2. CGLIB를 통해 프록시 클래스를 만듭니다
장점은 대상 객체가 인터페이스 원시 클래스를 구현할 필요가 없다는 것입니다.
public class clientbean {private String name = null; public clientbean () {} public clientbean (문자열 이름) {this.name = name; } public void addclient () {System.out.println ( "이것은 addclient () 메소드입니다!"); } public void deleteclient () {system.out.println ( "이것은 deleteclient () 메소드입니다!"); } public void getClient () {System.out.println ( "this is getClient () 메소드!"); } public void getClient () {System.out.println ( "this is getClient ()) 메소드!"); } public void updateClient () {system.out.println ( "이것은 updateClient () 메소드입니다!"); } public String getClientName () {return name; } public void setclientName (문자열 이름) {this.name = 이름; }} 에이전트 클래스
import java.lang.reflect.method; com.cignacmc.finance.bean.clientbean import; import net.sf.cglib.proxy.enhancer; import net.sf.cglib.proxy.methodinterceptor; import net.sf.cglib.proxy.methodinterceptor; import net.sf.cglib.proxy.methodproxy; 공개 클래스 CGLIBPROXY는 MethodInterceptor {private object targetObject; 공개 물체 CreateProxyObject (Object TargetObject) {this.targetObject = targetObject; Enhancer Enhancer = New Enhancer (); Enhancer.setSuperClass (this.targetObject.getClass ()); Enhancer.setCallback (this); return enhancer.create (); } public Object Intercept (객체 프록시, 메소드 메소드, 개체 [] args, MethodProxy MethodProxy) 던지기 가능 {ClientBean ClientBean = (ClientBean) TargetObject; 문자열 username = clientBean.getClientName (); 객체 결과 = null; if (username! = null &&! "". } 반환 결과; }} 테스트 클래스
java.lang.reflect.proxy import; com.cignacmc.finance.bean.clientbean import; com.cignacmc.finance.bean.userbean import; com.cignacmc.finance.bean.userbeanimpl 가져 오기; com.cignacmc.finance.proxy.cglibproxy 가져 오기; com.cignacmc.finance.proxy.userbeanproxy 가져 오기; public class proxyexe {public static void main (String [] args) {System.out.println ( "........ cglib proxy ............"); System.out.println ( "증명 ..............."); cglibproxy cproxy = 새로운 cglibproxy (); ClientBean ClientBean = (ClientBean) cproxy.createProxyObject (New ClientBean ( "Bob Liang")); clientBean.AddClient (); System.out.println ( "입증 없음 ..............."); cproxy = 새로운 cglibproxy (); clientBean = (clientBean) cproxy.createProxyObject (new ClientBean ()); clientBean.AddClient (); }}
산출:
..... cglib proxy .................. 증명 ............ 이것은 addclient () 메소드입니다! 증명되지 않았다 ............