SpringAOP

AOP面向切面编程 Spring是基于Aspectj的AOP开发

AOP的底层原理就是动态代理

动态代理分两种 JDK动态代理:只能对实现了接口的类产生代理 Cglib动态代理:第三方代理技术,对没有实现接口的类产生代理对象,生成子类对象,可以动态添加类的属性和方法

Spring会根据是否有接口自动选择相应的代理

术语: 连接点:可以被拦截的点 切入点:真正被拦截的点 通知:增强方法 引介:类的增强 目标:被增强的对象 织入:将增强应用到目标的过程 代理:织入增强后产生的对象 切面:切入点和通知的组合

通知类型:

前置通知: 目标方法执行之前进行操作,可以获得切入点信息 后置通知: 目标方法执行之后进行操作,可以获得方法的返回值 环绕通知: 目标方法执行之前和之后进行操作,可以阻止目标方法的执行 异常抛出通知: 程序出现异常时进行操作,可以获得抛出的异常信息 最终通知: 无论代码知否有异常,总是会执行

切入点表达式语法 [访问修饰符] 方法返回值 包名.类名.方法名(参数) public void com.jinke.spring.CustomerDao.save(..) * *.*.*.*Dao.save(..) * com.jinke.spring.CustomerDao+.save(..) * com.jinke.spring..*.*(..)

先介绍下两种动态代理

JDK的动态代理

public interface UserDao {
    public void save();
    public void update();
    public void find();
    public void delete();
}
public class UserDaoImpl implements UserDao {
    @Override
    public void save() {
        System.out.println("保存用户");
    }

    @Override
    public void update() {
        System.out.println("修改用户");
    }

    @Override
    public void find() {
        System.out.println("查询用户");
    }

    @Override
    public void delete() {
        System.out.println("删除用户");
    }
}
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class JdkProxy implements InvocationHandler {

    private UserDao userDao;

    public JdkProxy(UserDao userDao) {
        this.userDao = userDao;
    }

    public UserDao createProxy() {
        UserDao userDaoProxy = (UserDao) Proxy.newProxyInstance(userDao.getClass().getClassLoader(),
                userDao.getClass().getInterfaces(), this);
        return userDaoProxy;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //判断方法名是不是save
        if ("save".equals(method.getName())) {
            //增强
            System.out.println("权限校验的代码====");
            return method.invoke(userDao, args);
        }
        return method.invoke(userDao, args);
    }
}

执行

import org.junit.Test;

public class Demo {
    @Test
    public void demo() {
        UserDao userDao = new UserDaoImpl();
        UserDao proxy = new JdkProxy(userDao).createProxy();
        proxy.save();
        proxy.update();
        proxy.find();
        proxy.delete();
    }
}

输出结果

权限校验的代码====
保存用户
修改用户
查询用户
删除用户

Cglib的动态代理

public class CustomerDao {
    public void save() {
        System.out.println("保存用户");
    }

    public void update() {
        System.out.println("修改用户");
    }

    public void find() {
        System.out.println("查询用户");
    }

    public void delete() {
        System.out.println("删除用户");
    }
}
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 {
    private CustomerDao customerDao;

    public CglibProxy(CustomerDao customerDao) {
        this.customerDao = customerDao;
    }

    public CustomerDao createProxy() {
        Enhancer enhancer = new Enhancer();
        //设置父类
        enhancer.setSuperclass(customerDao.getClass());
        //设置回调(类似于InvocationeHnadler对象)
        enhancer.setCallback(this);
        //创建代理对象
        CustomerDao proxy = (CustomerDao) enhancer.create();
        return proxy;
    }

    @Override
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        if ("save".equals(method.getName())) {
            //增强
            System.out.println("权限校验的代码====");
            methodProxy.invokeSuper(proxy, args);
        }
        return methodProxy.invokeSuper(proxy, args);
    }
}

执行

import org.junit.Test;

public class Demo {
    @Test
    public void demo() {
        CustomerDao customerDao = new CustomerDao();
        CustomerDao proxy = new CglibProxy(customerDao).createProxy();
        proxy.save();
        proxy.update();
        proxy.find();
        proxy.delete();
    }
}

输出结果

权限校验的代码====
保存用户
保存用户
修改用户
查询用户
删除用户

AOP和IOC一样,也有XML和注解两种方式

XML方式:

public interface ProductDao {
    public void save();

    public void update();

    public void find();

    public String delete();
}
public class ProductDaoImpl implements ProductDao {

    @Override
    public void save() {
        System.out.println("保存商品");
    }

    @Override
    public void update() {
        System.out.println("修改商品");
    }

    @Override
    public void find() {
        System.out.println("查询商品");
        int i = 1 / 0;
    }

    @Override
    public String delete() {
        System.out.println("删除商品");
        return "二傻";
    }
}
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;

/**
 * 切面类
 */
public class MyAspectXML {

    public void checkPri(JoinPoint joinPoint) {
        System.out.println("权限校验===" + joinPoint);
    }

    public void writeLog(Object result) {
        System.out.println("日志记录===" + result);
    }

    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("环绕前通知====");
        Object obj = joinPoint.proceed();
        System.out.println("环绕后通知====");
        return obj;
    }

    public void afterThrowing(Throwable ex) {
        System.out.println("异常抛出通知===" + ex);
    }

    public void after() {
        System.out.println("最终通知");
    }
}

配置文件ApplicationComtext4.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

    <!--配置目标对象:被增强的对象-->
    <bean id="productDao" class="com.jinke.aopxml.ProductDaoImpl"/>
    <!--将切面类交给Spring管理-->
    <bean id="myAspect" class="com.jinke.aopxml.MyAspectXML"/>

    <!--通过AOP的配置完成对目标类产生代理-->
    <aop:config>
        <!--表达式配置哪些类的那些方法需要进行增强-->
        <aop:pointcut id="pointcut1" expression="execution(* com.jinke.aopxml.ProductDaoImpl.save(..))"/>
        <aop:pointcut id="pointcut2" expression="execution(* com.jinke.aopxml.ProductDaoImpl.delete(..))"/>
        <aop:pointcut id="pointcut3" expression="execution(* com.jinke.aopxml.ProductDaoImpl.update(..))"/>
        <aop:pointcut id="pointcut4" expression="execution(* com.jinke.aopxml.ProductDaoImpl.find(..))"/>

        <!--配置切面-->
        <aop:aspect ref="myAspect">
            <!--前置通知-->
            <aop:before method="checkPri" pointcut-ref="pointcut1"/>
            <!--后置通知-->
            <aop:after-returning method="writeLog" pointcut-ref="pointcut2" returning="result"/>
            <!--环绕通知-->
            <aop:around method="around" pointcut-ref="pointcut3"/>
            <!--异常抛出通知-->
            <aop:after-throwing method="afterThrowing" pointcut-ref="pointcut4" throwing="ex"/>
            <!--最终通知-->
            <aop:after method="after" pointcut-ref="pointcut4"/>
        </aop:aspect>
    </aop:config>
</beans>

执行

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import javax.annotation.Resource;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:ApplicationContext4.xml")
public class SpringDemo {
    @Resource(name = "productDao")
    private ProductDao productDao;

    @Test
    public void demo() {
        productDao.save();
        productDao.update();
        productDao.find();
        productDao.delete();
    }
}

输出结果

权限校验===execution(void com.jinke.aopxml.ProductDao.save())
保存商品
环绕前通知====
修改商品
环绕后通知====
查询商品
最终通知
异常抛出通知===java.lang.ArithmeticException: / by zero

注解的方式

public class OrderDao {
    public void save() {
        System.out.println("保存订单");
    }

    public void update() {
        System.out.println("修改订单");
    }

    public String delete() {
        System.out.println("删除订单");
        return "三傻";
    }

    public void find() {
        System.out.println("查询订单");
        int i = 1 / 0;
    }
}
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;

@Aspect
public class MyAspectAnno {

    @Before(value = "MyAspectAnno.pointcutSave()")
    public void before() {
        System.out.println("前置通知");
    }

    @AfterReturning(value = "MyAspectAnno.pointcutDelete()", returning = "result")
    public void afterReturn(Object result) {
        System.out.println("后置增强==" + result);
    }

    @Around(value = "MyAspectAnno.pointcutUpdate()")
    public void around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("前置环绕");
        joinPoint.proceed();
        System.out.println("后置环绕");
    }

    @AfterThrowing(value = "MyAspectAnno.pointcutFind()", throwing = "ex")
    public void afterThrowing(Throwable ex) {
        System.out.println("异常抛出==" + ex.getMessage());
    }

    @After(value = "MyAspectAnno.pointcutFind()")
    public void after() {
        System.out.println("最终通知");
    }

    /**
     * 切入点注解
     */
    @Pointcut(value = "execution(* com.jinke.aopanno.OrderDao.find())")
    private void pointcutFind() {
    }

    @Pointcut(value = "execution(* com.jinke.aopanno.OrderDao.save())")
    private void pointcutSave() {
    }

    @Pointcut(value = "execution(* com.jinke.aopanno.OrderDao.update())")
    private void pointcutUpdate() {
    }

    @Pointcut(value = "execution(* com.jinke.aopanno.OrderDao.delete())")
    private void pointcutDelete() {
    }
}

配置文件ApplicationContext5.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
    <!--在配置文件中开启注解AOP的开发-->
    <aop:aspectj-autoproxy/>

    <bean id="orderDao" class="com.jinke.aopanno.OrderDao"/>
    <bean id="myAspect" class="com.jinke.aopanno.MyAspectAnno"/>
</beans>

执行

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import javax.annotation.Resource;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:ApplicationContext5.xml")
public class SpringDemo {

    @Resource
    private OrderDao orderDao;

    @Test
    public void demo() {
        orderDao.save();
        orderDao.update();
        orderDao.delete();
        orderDao.find();
    }
}

输出结果

前置通知
保存订单
前置环绕
修改订单
后置环绕
删除订单
后置增强==三傻
查询订单
最终通知
异常抛出==/ by zero

简单来说,AOP动态代理是为了在不改变源码的前提下,在源码某个方法前,插入执行自己的方法。Android插件化中Hook也是用到的动态代理的思想,如出一辙

本文分享自微信公众号 - 安卓圈(gh_df75572d44e4),作者:King磊

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-06-13

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Hibernate文件配置

    映射需要通过XML的配置文件来完成,这个配置文件尽量统一(xxx.hbm.xml) Hibernate核心的配置:必须的配置、可选的配置、映射文件的引入

    用户3112896
  • Activity插件化解决方案

    2.最简单的插件化方案就是在宿主的androidmanifest.xml中申明插件中的四大组件

    用户3112896
  • Spring事务管理

    事务的特性: 原子性:事务不可分割 一致性:事务执行前后数据完整性保持一致 隔离性:一个事务的执行不应该受到其他事务的干扰 持久性:一旦事务结束,数据就持久到数...

    用户3112896
  • (Head First 设计模式)学习笔记(3) --装饰者模式(StarBuzz咖啡店实例)

    应用概述: StarBuzz咖啡店有很多饮料,每种饮料都可以根据客户需要加一些调料,比如深培咖啡可以加摩卡(或双倍摩卡),而且某些饮料可以分为大中小杯,根据容...

    菩提树下的杨过
  • 【设计模式自习室】建造者模式

    复杂对象相当于一辆有待建造的汽车,而对象的属性相当于汽车的部件,建造产品的过程就相当于组合部件的过程。由于组合部件的过程很复杂,因此,这些部件的组合过程往往被“...

    后端技术漫谈
  • Java常用设计模式

    工厂是干嘛的,就是用来生产的嘛,这里说的工厂也是用来生产的,它是用来生产对象的。也就是说,有些对象我们可以在工厂里面生产,需要用时直接从工厂里面拿出来即可,而不...

    贪挽懒月
  • .NET基础拾遗(2)面向对象的实现和异常的处理基础

      在C#中申明一个类型时,只支持单继承(即继承一个父类),但支持实现多个接口(Java也是如此)。像C++可能会支持同时继承自多个父类,但.NET的设计小组认...

    Edison Zhou
  • 在C#中使用依赖注入-工厂模式和工厂方法模式

    工厂模式和工厂方法模式是设计模式中较为常见的两种模式,借助于依赖注入可以更好的发挥模式的特性。本文将通过一个业务需求的变化过程来阐述如何更好的使用设计模式与依赖...

    newbe36524
  • 初探Java设计模式2:结构型模式(代理模式,适配器模式等)

    转自https://javadoop.com/post/design-pattern

    Java技术江湖
  • java设计模式-适配器

    适配器模式把一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作。 类适配器模式

    曼路

扫码关注云+社区

领取腾讯云代金券