增强方法的方式

最近在看Spring的一些知识,看到AOP就想总结下有关 增强一个方法的知识。

  • 我在这里介绍4种方式:
    1. 继承
    2. 装饰设计模式
    3. JDK的动态代理
    4. CGlib

  • 继承
    1. 用法。
      继承你要增强的方法的类,重写你要增强的方法,在方法体内进行增强。
      创建增强后的对象调用方法。
    2. 缺点。
      假如我们想要增强的方法是一个接口里面的。
      比如Servlet里的HttpServletRequest里的getParameter(String name)让它具有过滤敏感字符的功能,但是你发现HttpServletRequest是一个接口。
    3. 示例。
> 需求在保存用户前后开启事务和提交事务
> UserServiceImpl

public class UserServiceImpl implements IUserService{
    //持有dao对象
    private IUserDao userDao;
    //保存一个用户
    public void save(User user){
        userDao.save(user);
    }
}
public class MyUserServiceImpl  extends UserServiceImpl{
    //重写save()方法
    public void save(User user){
        //开始增强
        syso("开启事务...");
        super.save(user);
        syso("提交事务...");
    }
}

  • 装饰设计模式
    1. 用法。
      1. 条件。
        1. 与目标类实现同一个接口。
        2. 增强类中要有被增强类的引用。
        3. 在增强类中添加增强的方法。
      2. 使用。
        1. 创建增强类的对象,传入目标类的对象。
        2. 用增强类来调用方法 。
    2. 缺点。
      1. 假如接口中方法太多,都需要实现。
      2. 虽然适配器模式能解决,但是一般没人用。
    3. 示例。
public class MyUserServiceImpl implements IUserService{
    private IUserService  userService;
    //持有被增强类
    public MyUserServiceImpl(IUserService userService){
        this.userService=userService;
    }
    public viod save(User user){
        //开始增强
        syso("开启事务..");
        userService.save();
        syso("提交事务..");
    }
}

  • JDK提供的动态代理

    1. 条件。
      1. 需要目标类实现接口。
    2. 用法。
      1. 通过Proxy.newInstance(参数后介绍)来动态生成增强的对象。
      2. 运用生成的对象来调用方法。
    3. 关系。
      1. 代理类和目标类是兄弟关系。(实现了相同的接口)
    4. 示例。
@Test
public void testDynamic(){
    /*
     * 为什么局部内部类调用的局部变量要加final修饰
     *    因为局部内部类要编译成一份独立的class文件,
     * 当前线程运行结束时局部变量要被垃圾回收器回收,但是内部类还需要这个变量,
     * 所以将局部变量加final修饰变成常量。
     */
    final IUser user = new User();
    //返回值.增强后的对象
    IUser newUser = (IUser)Proxy.newProxyInstance(
        //参数1.与目标类相同的类加载器
        //只有相同的类加载器加载的类才能互相调用
        user.getClass().getClassLoader(),
        //参数2.目标类实现的所有接口
        //也就是获得目标类上的方法 
        user.getClass().getInterfaces(),
        //参数3.InvocationHandler实现类
        new InvocationHandler() {

            @Override
            public Object invoke(
                //参数1.代理出来的对象 一般不用关心
                Object proxy,
                //参数2.正在代理的方法
                Method method, 
                //参数3.正在代理的方法需要的参数
                Object[] args) throws Throwable {

            //省略if("save".equals(method.getName()))只增强save方法

            //开始增强
            System.out.println("开启事务..");
            //接收原方法的返回值
            //用原对象调用原方法,学习反射知识时用过
            Object invoke = method.invoke(user, args);
            System.out.println("关闭事务..");
            //将接受的返回值返回
            return invoke;
        }

    });
    //用代理出来的对象来调用方法,反编译可知实质调用的invoke方法。
    newUser.save();
}

  • CGlib提供的动态代理

    1. 条件。
      1. 只需要目标类,且不被final修饰的类。
    2. 用法。
      1. 导包(Spring项目不需要)。
      2. 通过Enhance.creat( 参数后介绍 )来获取增强的对象
      3. 用增强的对象来调用方法。
    3. 关系。
      1. 代理类和目标类是父子关系。
    4. 示例。
@Test
public void testDynamic(){
    //加final修饰
    final User user=new User();
    User newUser = (User)Enhancer.create(
        //参数1.目标类字节码文件
        //根据此参数可以获得相同的类加载器和方法
        user.getClass(), 
        //参数2.局部内部类
        new MethodInterceptor() {

            @Override
            public Object intercept(
                //参数1.代理对象类型 忽略
                Object arg0, 
                //正在代理的方法
                Method method,
                //正在代理的方法需要的参数 
                Object[] args, 
                //方法的代理 一般不用
                MethodProxy arg3) throws Throwable {
                //省略if("save".equals(method.getName()))只增强save方法
                    //开始增强
                    System.out.println("开启事务");
                    //接收原方法的返回值
                    //用原对象调用原方法,学习反射知识时用过
                    Object invoke = method.invoke(user, args);
                    System.out.println("关闭事务");
                    //返回接收的返回值
                    return invoke;
            }
        });
    newUser.save();
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值