spring AOP-动态代理实现

AOP

AOP:面向切面的编程。
OOP编程是面向对象的编程方法,各个对象之间进行信息交互,实现业务逻辑,是横向的实现方法,而AOP是OOP方法的补充,是一种纵向逻辑的处理。如:当业务逻辑已经基本编写完成,但是客户提出一个新需求,需要对所有业务进行一种安全审计的记录,以用于各种管理的认证,这个时候如果继续使用OOP编程的话,需要增加公共类,子类再去继承;或者增加一个接口,然后各个子类再去实现接口方法,就需要编写大量大量来处理,这样我们的代码就会变的更加臃肿,不利于后期的升级维护。
在这里插入图片描述
对象之间是oop编程,对于oop无法处理的纵向信息使用aop切面编程。
如果要了解aop,就需要了解动态代理技术

动态代理

spring的动态代理可以通过基于接口的代理和cglb代理实现

接口代理实现

下面通过一个例子来实现接口动态代理

package com.example.inf;

/*
 * 接口信息
 * */
public interface IUserDao {
    //增加
    void addUser();
    //删除
    void deleteUser();
}

接口实现

package com.example.inf.impl;

import com.example.inf.IUserDao;

public class UserDaoImp implements IUserDao {
    public void addUser() {
        System.out.println("新增用户方法");
    }

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

正常业务完成后,需要增加对代码的权限和日志记录,因此增加增强类处理方法

package com.example.aspect;

public class Myaspect {
    public  void check_Permissions(){
        System.out.println("检查数据权限");
    }

    public void log(){
        System.out.println("打印日志");
    }
}

增加代理类,用于增强接口方法处理

package com.example.proxy;

import com.example.aspect.Myaspect;
import com.example.inf.IUserDao;

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

/*
* 创建代理类
* */
public class jdkProxy {

    private IUserDao userDao;

    public IUserDao getUserDao(final IUserDao userDao)
    {
        this.userDao=userDao;

        return (IUserDao) Proxy.newProxyInstance(userDao.getClass().getClassLoader(), userDao.getClass().getInterfaces(),
                new InvocationHandler() {
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        Myaspect myaspect=new Myaspect();
                        myaspect.check_Permissions();
                        Object obj=method.invoke(userDao,args);
                        myaspect.log();
                        return obj;
                    }
                });
    }
}

可以看到是通过Proxy.newProxyInstance方法来实现,它的方法体如下:

  /**
     * Returns an instance of a proxy class for the specified interfaces
     * that dispatches method invocations to the specified invocation
     * handler.
     * 返回一个代理类的实例方法
     *
     * <p>{@code Proxy.newProxyInstance} throws
     * {@code IllegalArgumentException} for the same reasons that
     * {@code Proxy.getProxyClass} does.
     *
     * @param   loader the class loader to define the proxy class
     * 要增强的类
     * @param   interfaces the list of interfaces for the proxy class
     *          to implement
     * 要增强类的接口
     * @param   h the invocation handler to dispatch method invocations to
     * 要增强的方法
     * @return  a proxy instance with the specified invocation handler of a
     *          proxy class that is defined by the specified class loader
     *          and that implements the specified interfaces
     * @throws  IllegalArgumentException if any of the restrictions on the
     *          parameters that may be passed to {@code getProxyClass}
     *          are violated
     * @throws  SecurityException if a security manager, <em>s</em>, is present
     *          and any of the following conditions is met:
     *          <ul>
     *          <li> the given {@code loader} is {@code null} and
     *               the caller's class loader is not {@code null} and the
     *               invocation of {@link SecurityManager#checkPermission
     *               s.checkPermission} with
     *               {@code RuntimePermission("getClassLoader")} permission
     *               denies access;</li>
     *          <li> for each proxy interface, {@code intf},
     *               the caller's class loader is not the same as or an
     *               ancestor of the class loader for {@code intf} and
     *               invocation of {@link SecurityManager#checkPackageAccess
     *               s.checkPackageAccess()} denies access to {@code intf};</li>
     *          <li> any of the given proxy interfaces is non-public and the
     *               caller class is not in the same {@linkplain Package runtime package}
     *               as the non-public interface and the invocation of
     *               {@link SecurityManager#checkPermission s.checkPermission} with
     *               {@code ReflectPermission("newProxyInPackage.{package name}")}
     *               permission denies access.</li>
     *          </ul>
     * @throws  NullPointerException if the {@code interfaces} array
     *          argument or any of its elements are {@code null}, or
     *          if the invocation handler, {@code h}, is
     *          {@code null}
     */
    @CallerSensitive
    public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
    {
        Objects.requireNonNull(h);

        final Class<?>[] intfs = interfaces.clone();
        final SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
        }

        /*
         * Look up or generate the designated proxy class.
         */
        Class<?> cl = getProxyClass0(loader, intfs);

        /*
         * Invoke its constructor with the designated invocation handler.
         */
        try {
            if (sm != null) {
                checkNewProxyPermission(Reflection.getCallerClass(), cl);
            }

            final Constructor<?> cons = cl.getConstructor(constructorParams);
            final InvocationHandler ih = h;
            if (!Modifier.isPublic(cl.getModifiers())) {
                AccessController.doPrivileged(new PrivilegedAction<Void>() {
                    public Void run() {
                        cons.setAccessible(true);
                        return null;
                    }
                });
            }
            return cons.newInstance(new Object[]{h});
        } catch (IllegalAccessException|InstantiationException e) {
            throw new InternalError(e.toString(), e);
        } catch (InvocationTargetException e) {
            Throwable t = e.getCause();
            if (t instanceof RuntimeException) {
                throw (RuntimeException) t;
            } else {
                throw new InternalError(t.toString(), t);
            }
        } catch (NoSuchMethodException e) {
            throw new InternalError(e.toString(), e);
        }
    }

测试

package com.example.ui;

import com.example.inf.IUserDao;
import com.example.inf.impl.UserDaoImp;
import com.example.proxy.jdkProxy;

public class Client {
    public static void main(String[] args) {
        //创建代理类
        jdkProxy jdkProxy=new jdkProxy();
        //创建目标对象
        IUserDao userDao=new UserDaoImp();
        //从代理对象获取增强后的目标对象
        IUserDao userDaoZengQ=jdkProxy.getUserDao(userDao);
        //执行增强后的方法
        userDaoZengQ.addUser();
        userDaoZengQ.deleteUser();
    }
}

输出:
检查数据权限
新增用户方法
打印日志
检查数据权限
删除用户方法
打印日志
可以看出基于接口的动态代理类通过反射方法确实对我们的方法进行了加强,实现了目的,但是这种方法有局限性,如果要增强的方法不是接口的实现类,就不能使用了。

cglib代理

CGLIB是一个高性能开源的代码生成包,采用底层的字节码技术,对指定的目标类生成一个子类,并对子类进行增强。
下面通过一个例子来演示CGLIB动态代理
增加一个具体类,具体类中没实现接口。

package com.example.inf;

public class PeopleDao {

    public void eat(){
        System.out.println("吃饭");
    }

    public void sleep(){
        System.out.println("睡觉");
    }
}

增加一个代理类enhancer.create

package com.example.proxy;
import com.example.aspect.Myaspect;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class CglibProxy {

    public Object CreateProxy(final Object target){
        Enhancer enhancer=new Enhancer();
        return (Object)enhancer.create(target.getClass(), new MethodInterceptor() {
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                Myaspect myaspect=new Myaspect();
                myaspect.check_Permissions();
                Object obj= method.invoke(target,objects);
                myaspect.log();
                return obj;
            }
        });
    }
}

测试类

package com.example.ui;

import com.example.inf.PeopleDao;
import com.example.proxy.CglibProxy;

public class CglibClient {
    public static void main(String[] args) {
        //创建代理对象
        CglibProxy cglibProxy=new CglibProxy();
        //创建目标对象
        PeopleDao peopleDao=new PeopleDao();
        //获取增强后的目标对象
        PeopleDao peopleDaoZengQ=(PeopleDao) cglibProxy.CreateProxy(peopleDao);
        //调用方法
        peopleDaoZengQ.eat();
        peopleDaoZengQ.sleep();
    }
}

输出
检查数据权限
吃饭
打印日志
检查数据权限
睡觉
打印日志

总结

可以看出基于接口的Proxy和cglib的enhancer.create方法创建的动态代理可以实现动态增强方法。
理解动态代理可以理解后面的AOP方法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值