Spring AOP及动态代理

软件发布|下载排行|最新软件

当前位置:首页IT学院IT技术

Spring AOP及动态代理

AOP   2022-05-28 我要评论

一. Spring AOP

       面向切面编程(Aspect Oriented Programming,AOP)是软件编程思想发展到一定阶段的产物,是对面向对象编程(Object Oriented Programming,OOP)的有益补充, 目前已成为一种比较成熟的编程方式。AOP适用于具有横向逻辑的场所,如访问控制、事务管理、性能监测等。

1. 传统问题:

      在传统的业务处理代码中,通常都会进行事务处理、日志记录等操作。虽然OOP可以通过组合或者继承的方式来达到代码的重用,但是比如实现日志记录时,代码还是会分散到不同的方法中。这样就会存在一个问题,如果想要关闭某个功能或者修改时,就必须要修改所有的相关方法。这不单单增加了开发人员的工作量,而且提高了代码的出错率。

2. 问题的解决策略:

      为了解决这个问题,AOP思想随之产生。AOP采取横向抽取机制,将分散在各个方法中的重复代码提取出来,然后在程序编译或运行时,再将这些提取出来的代码应用到需要执行的地方。这种采用横向抽取机制的方式,是传统的OOP思想无法办到的,因为OOP只能实现父子关系的纵向的重用。虽然AOP是一种新的编程思想,却不是OOP的替代品,它只是OOP的延申和补充。

3. AOP优点:

       AOP的使用让开发人员在编写业务逻辑时可以专心于核心业务,而不用过多地关注于其他业务逻辑的实现,这不但提高了开发效率,而且增强了代码的可维护性。

  在AOP思想中,类于切面的关系如下图所示。我们可以看出,通过Aspect(切面)分别在Class1和Class2的方法中加入了事务、日志、权限和异常等功能。

 二. 动态代理

      通过学习我们知道了AOP中的代理就是由AOP框架动态生成的一个对象,该对象可以作为目标对象使用,对于面向切面编程,简单地说,就是在不改变原程序的基础上为代码段增加新的功能,对代码段进行增强处理。它的设计思想来源于代理设计模式,通常情况下调用对象的方法如下图。

      在代理模式中可以为该对象设置一个代理对象,代理对象为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 动态代理的使用非常简单,但它具有一定的局限性(使用动态代理的对象必须实现一个或多个接口)如果要对没有实现接口的类进行代理,那么可以使用CGLIB代理。

         CGLIB(Code Generation Library)是一个高性能开源的代码生成包,它采用非常底层的字节码技术,对指定的目标类生成一个子类,并对子类进行增强。在Spring框架的核心包中已经集成了CGLIB所需要的包,所以开发中不需要另外导入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;
    }
}

结果:

Copyright 2022 版权所有 软件发布 访问手机版

声明:所有软件和文章来自软件开发商或者作者 如有异议 请与本站联系 联系我们