【SpringFramework】AOPとダイナミックプロキシの適用

一。春のAOP

       アスペクト指向プログラミング(AOP)は、特定の段階で考えられているソフトウェアプログラミングの開発の産物であり、オブジェクト指向プログラミング(OOP)の便利な補足であり、比較的成熟したプログラミング方法になっています。AOPは、アクセス制御、トランザクション管理、パフォーマンス監視などの水平ロジックを備えた場所に適しています。

1.従来の問題:

      従来のビジネス処理コードでは、通常、トランザクション処理やロギングなどの操作が実行されます。OOPは、たとえばロギングを実装する場合など、構成または継承を通じてコードの再利用を実現できますが、コードは依然としてさまざまなメソッドに分散しています。このように問題が発生します。関数をオフにしたり変更したりする場合は、関連するすべてのメソッドを変更する必要があります。これにより、開発者の作業負荷が増えるだけでなく、コードのエラー率も上がります。

2.問題解決戦略:

      この問題を解決するために、AOPのアイデアが生まれました。AOPは、水平抽出メカニズムを採用して、さまざまな方法で散在する反復コードを抽出し、これらの抽出されたコードを、プログラムのコンパイルまたは実行時に実行する必要のある場所に適用します。OOPは親子関係の垂直方向の再利用しか実現できないため、この水平抽出メカニズムを採用する方法は、従来のOOPの考え方では実現できません。AOPは新しいプログラミングのアイデアですが、OOPに代わるものではなく、OOPの単なる拡張および補足です

 3. AOPの利点:

       AOPを使用すると、開発者は他のビジネスロジックの実装にあまり注意を払うことなく、ビジネスロジックを作成するときにコアビジネスに集中できます。これにより、開発効率が向上するだけでなく、コードの保守性も向上します

  AOPの考え方では、クラスとアスペクトの関係を次の図に示します。トランザクション、ログ、アクセス許可、例外などの関数が、アスペクトを介してClass1Class2のメソッドに追加されていることがわかります。

 2.動的プロキシ

      学習を通じて、AOPのエージェントは、AOPフレームワークによって動的に生成されたオブジェクトであり、ターゲットオブジェクトとして使用できることがわかります。アスペクト指向プログラミングの場合、要するに、変更せずにコードセグメントに新しいコードを追加することです。元のprogram。コードセグメントを拡張する機能。そのデザインアイデアはプロキシデザインパターンに基づいています。通常、オブジェクトを呼び出す方法は次の図のようになります

 

      プロキシモードでは、オブジェクトにプロキシオブジェクトを設定でき、プロキシオブジェクトはfunction()のプロキシメソッドを提供します。元のオブジェクトのfunction()メソッドがプロキシオブジェクトのfunction()メソッドを介して呼び出された場合、プロキシメソッドを追加できます。新機能は拡張処理です。拡張関数は、元のオブジェクトのfunction()の前または後に挿入できます(点線など)

 

 1.JDK動的プロキシ

      JDK動的プロキシはjava.lang.reflect.Proxyクラスを介して実装され、ProxyクラスのnewProxyInstance()メソッドを呼び出してプロキシオブジェクトを作成できます。ビジネスインターフェイスを使用するクラスの場合、SpringフレームワークはデフォルトでJDK動的プロキシを使用してAOPを実装します。ケースを通してデモンストレーションします。

 1. UserDao.java

package dao;

public interface UserDao {
    public void addUserDao();
    public void deleteUser();
}

2. UserDaoImpl.java

package dao;

public class UserDaoImpl implements UserDao{
    @Override
    public void addUserDao() {
        System.out.println("添加用户");
    }

    @Override
    public void deleteUser() {
        System.out.println("删除用户");
    }
}

3. MyAspect.java

package aspect;

public class MyAspect {
    public void check_permission(){
        System.out.println("----模拟检查访问----");
    }
    public void log(){
        System.out.println("----模拟记录日记----");
    }
}

4. JdkProxy.java

package jdk;

import aspect.MyAspect;
import dao.UserDao;

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

/**
 * Jdk代理类
 */
public class JdkProxy implements InvocationHandler {
    //声明目标类接口
    private UserDao userdao;
//    创建代理方法
    public Object createProxy(UserDao userdao){
        this.userdao=userdao;
        //类加载器
        ClassLoader classLoader=JdkProxy.class.getClassLoader();
        //被代理对象实现的所有接口
        Class[] clazz=userdao.getClass().getInterfaces();
        //使用代理类进行增强,返回的是代理后的对象
        return Proxy.newProxyInstance(classLoader,clazz,this);
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //声明切面
        MyAspect myAspect=new MyAspect();
        //前增强
        myAspect.check_permission();
        //在目标上调用方法,并传入参数
        Object obj=method.invoke(userdao,args);
        //后增强
        myAspect.log();
        return obj;
    }
}

5. Test.java

    @Test
    public void shouldAnswerWithTrue()
    {
        JdkProxy jdkProxy=new JdkProxy();
        UserDao userDao=new UserDaoImpl();
        UserDao userDao1=(UserDao) jdkProxy.createProxy(userDao);
        userDao1.addUserDao();
        System.out.println("\n-----------------------------分割线------------------------------------\n");
        userDao1.deleteUser();
    }

結果:

2.CGLIBプロキシ

     JDK動的プロキシの使用は非常に簡単ですが、特定の制限があります(動的プロキシを使用するオブジェクトは、1つ以上のインターフェースを実装する必要があります)。インターフェースを実装しないクラスをプロキシする場合は、CGLIBプロキシを使用できます。

         CGLIB(コード生成ライブラリ)は、高性能のオープンソースコード生成パッケージであり、非常に低レベルのバイトコードテクノロジを使用して、指定されたターゲットクラスのサブクラスを生成し、サブクラスを拡張します。CGLIBに必要なパッケージは、Springフレームワークのコアパッケージに統合されているため、開発中にjarパッケージをインポートする必要はありません。

 1. BookDao.java

package dao;

public class BookDao {
    public void addBook(){
        System.out.println("添加书本");
    }
    public void deleteBook(){
        System.out.println("删除书本");
    }
}

2. CglibProxy.java

package jdk;


import aspect.MyAspect;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class CglibProxy implements MethodInterceptor {
    //代理方法
    public Object createProxy(Object target){
        Enhancer enhancer=new Enhancer();
        enhancer.setSuperclass(target.getClass());
        enhancer.setCallback(this);
        return enhancer.create();
    }

    @Override
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        MyAspect myAspect=new MyAspect();
        myAspect.check_permission();
        Object o1=methodProxy.invokeSuper(proxy,args);
        myAspect.log();
        return o1;
    }
}

結果:

 

おすすめ

転載: blog.csdn.net/m0_56233309/article/details/123793322