이 기사는 Java의 어려운 문제에 관한 것입니다. Java Core 라이브러리를 사용하여 간단한 AOP 메소드를 구현하고 인스턴스 코드를 분석하고 비교합니다. 다음은 모든 내용입니다.
Spring은 매우 인기있는 오픈 소스 프레임 워크이며 AOP (섹션 프로그래밍)는 Spring의 가장 중요한 개념 중 하나입니다. AOP의 아이디어를 더 잘 이해하고 배우기 위해 핵심 라이브러리를 사용하여 한 번에이를 달성하는 것이 좋습니다.
먼저 AOP의 개념을 소개하겠습니다. AOP (Aspect Oriented Programming), 즉 접선 지향 프로그래밍. 소위 접선 지향적 프로그래밍은 단면 영역의 관점에서 코드를 설계한다는 아이디어입니다. 전통적인 OOP 아이디어는 캡슐화 상속 및 다형성을 사용하여 수직 계층 관계를 구성하는 것이지만 수평 관계를 정의하는 데 적합하지 않습니다. AOP 아이디어는 이에 대한 좋은 보충제를 제공합니다.
예를 들어, 로그 관리 코드는 종종 많은 객체 수준에서 수평으로 흩어져 있지만 해당 객체의 핵심 함수와 관련이 없습니다. 허가 검증, 디버그 출력, 트랜잭션 처리 등과 같은 유사한 코드도 있습니다. 이것은 재사용 및 관리에 도움이되지 않습니다.
현재 AOP 기술이 시작되었습니다. "Crosscutting"기술을 사용하여 캡슐화 객체에 깊이 침투하여 여러 클래스에 영향을 미치는 일반적인 동작을 재사용 가능한 모듈로 캡슐화하고, "측면", 즉 슬라이싱을 명명합니다. 소위 "섹션"은 단순히 비즈니스와 관련이 없지만 비즈니스 모듈에 의해 공동으로 호출되는 논리 또는 책임에 의해 단순히 캡슐화되며, 이는 시스템의 중복 코드를 줄이고 모듈 간의 커플 링을 줄이며 후속 작동 가능성 및 유지 관리에 도움이됩니다.
그렇다면 AOP는 어떻게 구현됩니까?
대답은 동적 프록시입니다 (자세한 내용은 프록시에 대한 또 다른 장이 있으므로 자세한 내용은 여기에 가지 않을 것입니다). 동적 프록시를 구현하는 두 가지 방법이 있습니다. 하나는 JDK 동적 프록시이고 다른 하나는 CGLIB Dynamic Proxy입니다.
그런 다음 두 가지 방법을 사용하여 간단한 밤나무를 만듭니다.
먼저 시나리오를 설계해 보겠습니다. 컴퓨팅 인터페이스 ICalcigulator 와이 인터페이스를 구현하는 계산기 클래스 계산기 impl이 있다고 가정 해 봅시다.
공용 인터페이스 ICalculator {// 추가 작업 공개 int add (int a, int b); // subtraction public int suxtract (int a, int b); // 다중 공개 int 곱하기 (int a, int b); // 분할 공개 int 정의 (int a, int b);} public class calculatorimpl은 icalculator {@override public int add (int a, int b) {return a + b; } @override public int suxtract (int a, int b) {return a -b; } @override public int weptly (int a, int b) {return a * b; } @override public int define (int a, int b) {return a / b; }}원래 계산기 클래스의 내부 코드를 변경하지 않고 계산기 방법을 사용하는 총 횟수를 기록하는 방법은 무엇입니까?
다이내믹 프록시를 사용하면 실제로 매우 간단합니다. 먼저 클래스를 생성하고 InvocationHandler 인터페이스를 구현하고 호출 메소드를 재정의하십시오.
공개 클래스 테스트 핸들러는 호출 핸들러를 구현합니다. 개인 int 시간; // 대의원 객체를 바인딩하고 프록시 클래스 공개 객체 바인드 (Object TargetObject) {this.targetObject = targetObject; return proxy.newproxyInstance (targetObject.getClass (). getClassLoader (), targetObject.getClass (). getInterfaces (), this); } @override public object invoke (오브젝트 프록시, 메소드 메소드, 개체 [] args) 던지기 가능 {// (); 객체 결과 = method.invoke (targetObject, args); 후에(); 반환 결과; } private void 이전 () {system.out.println ( "계산하기 전에 무언가를 할 수 있습니다."); } private void at at () {usetimes ++; System.out.println ( "사용 :"+usetimes+"times"); }}코드가 너무 많지만 주요 메소드는 호출 메소드입니다. 객체 결과 = method.invoke (targetObject, args); 원래 매개 변수를 계속 사용하여 원래 메소드를 실행하는 것과 같습니다. 전후와 후에는 사용자 정의 된 함수이며, 여기서 사용량 수와 같이 객체 코드가 실행되기 전후에 수행 할 작업을 수행 할 수 있습니다.
BIND 방법에서, 대상 프록시 객체가 전달되고 프록시 클래스 인스턴스가 반환됩니다. 다음으로 사용 방법을 살펴 보겠습니다.
public class testproxy {public static void main (String [] args) {testhandler proxy = new testHandler (); icalculator acculate = (icalculator) proxy.bind (new calculatorimpl ()); int result = calculate.add (1,2); System.out.println ( "결과는 :"+결과); result = calculate.subtract (3,2); System.out.println ( "결과는 :"+결과); 결과 = 계산기. 다중 (4,6); System.out.println ( "결과는 :"+결과); 결과 = calculater.devide (6,2); System.out.println ( "결과는 :"+결과); }}먼저 TestHandler를 정의한 다음 BIND 메소드를 통해 프록시 인스턴스를 얻은 다음이 인스턴스를 직접 사용할 수 있습니다. 작업 결과는 다음과 같습니다.
우리는 계산하기 전에 무언가를 할 수 있습니다. 중고 : 1 결과 : 3 우리는 계산하기 전에 무언가를 할 수 있습니다. 사용 : 2 결과 : 1 우리는 계산하기 전에 무언가를 할 수 있습니다. 중고 : 3 결과 : 24 우리는 계산하기 전에 무언가를 할 수 있습니다. 사용 : 4 결과 : 3
이러한 방식으로 CalculatorImpl의 내부 코드를 수정하지 않고 코드 확장을 구현합니다.
그런 다음 CGLIB를 사용하여 한 번 구현하십시오.
먼저 클래스를 생성하여 Methodinterceptor 인터페이스를 구현하고 인터셉트 메소드를 대체하십시오. 다른 코드는 JDK 프록시 사용과 유사하지만 프록시 객체를 얻는 프로세스는 다릅니다.
공개 클래스 CGLIBPROXY는 MethodInterceptor {private int usetimes; 개인 객체 목표; 공개 객체 GetInstance (객체 대상) {this.target = target; Enhancer Enhancer = New Enhancer (); Enhancer.setSuperClass (this.target.getClass ()); Enhancer.setCallback (this); return enhancer.create (); } @Override public Object Intercept (Object O, Method Method, Objects, MethodProxy MethodProxy) 던지기 가능 {이전 (); 객체 결과 = MethodProxy.invokesuper (O, Objects); 후에(); 반환 결과; } private void 이전 () {system.out.println ( "계산하기 전에 무언가를 할 수 있습니다."); } private void at at () {usetimes ++; System.out.println ( "사용 :"+usetimes+"times"); }}테스트 :
공개 클래스 testcglibproxy {public static void main (String [] args) {cglibproxy cglibproxy = new cglibproxy (); icalculator 계산 = (icalculator) cglibproxy.getinstance (new calculatorimpl ()); int result = calculate.add (1,2); System.out.println ( "결과는 :"+결과); result = calculate.subtract (3,2); System.out.println ( "결과는 :"+결과); 결과 = 계산. 다중 (4,6); System.out.println ( "결과는 :"+결과); 결과 = 계산 .devide (6,2); System.out.println ( "결과는 :"+결과); }}작업 결과는 다음과 같습니다.
우리는 계산하기 전에 무언가를 할 수 있습니다. 중고 : 1 결과 : 3 우리는 계산하기 전에 무언가를 할 수 있습니다. 사용 : 2 결과 : 1 우리는 계산하기 전에 무언가를 할 수 있습니다. 중고 : 3 결과 : 24 우리는 계산하기 전에 무언가를 할 수 있습니다. 사용 : 4 결과 : 3
이제 우리는 같은 결과를 얻습니다. (두 개의 패키지가 필요합니다.
두 방법 모두 고유 한 강점이 있습니다. JDK 프록시는 프록시를 구현하기 전에 인터페이스를 설정해야합니다. 이것은 단점과 장점입니다. 단점은 이것이 조금 더 번거롭게 될 것이며, 이미 캡슐화 된 사람을 프록시 할 수 없으며 인터페이스를 구현하지 않는다는 것입니다. CGLIB 프록시 방법은 인터페이스를 사용하지 않아도됩니다. 그러나 JDK 프록시는 클래스에서 인터페이스를 덮어 쓰는 메소드 만 차단하는 반면 CGLIB는 클래스의 모든 메소드 호출을 가로 채고 있습니다. 둘 다 장단점이 있으므로 특정 상황을 분석해야합니다. 봄에는 두 개의 프록시 모드가 혼합되어 있습니다.