springAop开发入门

1. 认识什么是AOP

首先先给出一段比较专业的术语:
在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方
式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个
热点,也是Spring框架中的一个重要内容.
作用:
利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

2. AOP的相关概念

Aspect(切面): Aspect 声明类似于 Java 中的类声明,在 Aspect 中会包含着一些 Pointcut 以及相应的 Advice。
Joint point(连接点):表示在程序中明确定义的点,典型的包括方法调用,对类成员的访问以及异常处理程序块的执行等等,它自身还可以嵌套其它 joint point。
Pointcut(切点):表示一组 joint point,这些 joint point 或是通过逻辑关系组合起来,或是通过通配、正则表达式等方式集中起来,它定义了相应的 Advice 将要发生的地方。
Advice(增强):Advice 定义了在 Pointcut 里面定义的程序点具体要做的操作,它通过 before、after 和 around 来区别是在每个 joint point 之前、之后还是代替执行的代码。
Target(目标对象):织入 Advice 的目标对象.。
Weaving(织入):将 Aspect 和其他对象连接起来, 并创建 Adviced object 的过程

小结: 也就是说, 在 Spring AOP 中 Joint point 指代的是所有方法的执行点, 而 point cut 是一个描述信息, 它修饰的是 Joint point, 通过 point cut, 我们就可以确定哪些 Joint point 可以被织入 Advice, 切面可以理解成代理的对象, 目标对象就是需要织入 Advice 的对象.

注意: AOP中的Joinpoint可以有多种类型:构造方法调用,字段的设置和获取,方法的调用,方法的执行,异常的处理执行,类的初始化。也就是说在AOP的概念中我们可以在上面的这些Joinpoint上织入我们自定义的Advice,但是在Spring中却没有实现上面所有的joinpoint,确切的说,Spring只支持方法执行类型的Joinpoint。

3. Advice 的类型

before advice, 在 join point 前被执行的 advice. 虽然 before advice 是在 join point 前被执行, 但是它并不能够阻止 join point 的执行, 除非发生了异常(即我们在 before advice 代码中, 不能人为地决定是否继续执行 join point 中的代码)

after return advice, 在一个 join point 正常返回后执行的 advice

after throwing advice, 当一个 join point 抛出异常后执行的 advice
after(final) advice, 无论一个 join point 是正常退出还是发生了异常, 都会被执行的 advice.
around advice, 在 join point 前和 joint point 退出后都执行的 advice. 这个是最常用的 advice.
introduction,introduction可以为原有的对象增加新的属性和方法。

4. 两种底层实现(再底层就是反射)

4.1 JDK动态代理

在service包中
写接口

package service;

public interface UserService {

    public void save();

}

写实现类(目标类)

public class UserServiceImpl implements UserService {

    @Override
    public void save() {
        System.out.println("save running...");
    }
}

写通知类(有曾强的方法)

//通知类, 也就是抽取出来的增强方法
public class Advice {

    public void before(){
        System.out.println("前置增强...");
    }

    public void afterReturning(){
        System.out.println("后置增强...");
    }
}

测试

public class ProxyTest {
    @Test
    public void test1(){
        //获取目标对象
        final UserServiceImpl userService = new UserServiceImpl();

        //获取曾强方法的对象
        final Advice advice = new Advice();

        //返回值就是动态生成的代理对象
        /**
         * 三个参数
         * 目标对象的类加载器
         * 接口字节码对象数组
         * 调用操作者(代理类具体的操作内容)
         */
        UserService proxy = (UserService) Proxy.newProxyInstance(userService.getClass().getClassLoader(), userService.getClass().getInterfaces(),
                new InvocationHandler(){
                    /**
                     * 调用代理对象执行任何方法, 执行的都是invoke
                     * @param proxy 代理对象
                     * @param method  要进行曾强的目标方法对象
                     * @param args 代理对象调用方法时实际传递的参数对象
                     * @return
                     * @throws Throwable
                     */
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{
                        advice.before();
                        Object invoke = method.invoke(userService, args);//执行目标方法
                        advice.afterReturning();
                        return invoke;
                    }
                }

        );

        proxy.save();
    }
}

前置增强...
save running...
后置增强...

4.2 cglib动态代理

不需要接口
这个是第三方的, 是需要导jar包的
spring-context5.0.5的core中有cglib, 已经被集成进去了
在这里插入图片描述

    //cglib模式
    @Test
    public void test2(){
        //获取目标对象
        final UserServiceImpl userService = new UserServiceImpl();

        //获取曾强方法的对象
        final Advice advice = new Advice();

        //返回值就是动态生成了代理对象, 基于cglib
        //1. 创建曾强器
        Enhancer enhancer = new Enhancer();
        //2. 为增强器设置父类(目标)
        enhancer.setSuperclass(UserServiceImpl.class);
        //3. 设置回调
        enhancer.setCallback(new MethodInterceptor() {
            /**
             * 和jdk不一样, 有四个参数, 前三个一样, 最后一个是, 方法对象
             * @param o
             * @param method
             * @param objects
             * @param methodProxy
             * @return
             * @throws Throwable
             */
            @Override
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                advice.before();
                Object invoke = method.invoke(userService, objects);  //
                advice.afterReturning();
                return invoke;
            }
        });
        //4. 创建代理对象
        UserServiceImpl o = (UserServiceImpl) enhancer.create();

        o.save();
    }

5. AOP开发明确的事项

5.1 需要编写的内容

  • 编写核心业务代码
  • 编写切面类
  • 在配置文件中, 配置织入关系

5.2 AOP技术实现的内容

Spring框架监控切入点的执行, 一旦监控到切入点执行了, 使用代理机制, 动态的创建目标对象的代理对象, 代理对象会根据切点的的通知类型, 完成对应的增强.

5.3 AOP底层使用哪种代理逻辑

在spring中, 框架会依据目标类是否实现了接口来决定采用哪种动态代理的方式.

6. AOP的开发

6.1 基于xml的AOP开发

6.1.1 导包

	<dependency>
          <!--aop的jar包-->
          <groupId>org.aspectj</groupId>
          <artifactId>aspectjweaver</artifactId>
          <version>1.8.13</version>
      </dependency>

6.1.2 配置织入关系

<!--Aop配置-->
    <bean id="userService" class="service.serviceimpl.UserServiceImpl" />
    <bean id="advice" class="service.serviceimpl.proxy.Advice" />
    <!--配置织入: 告诉spring框架要对哪些方法进行曾强-->
    <aop:config>
        <!--声明切面-->
        <aop:aspect ref="advice">
            <!--声明通知类型, 切点表达式-->
            <aop:before method="before" pointcut="execution(public void service.serviceimpl.UserServiceImpl.save())"/>
        </aop:aspect>
    </aop:config>

测试

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class AopTest {

    @Autowired
    private UserService userService;

    @Test
    public void test1(){
        userService.save();
    }
}
前置增强...
save running...

6.1.3 小结

在这里插入图片描述

6.2 基于注解的AOP开发

在这里插入图片描述

@Aspect : 标注该类是一个切面类
在切点上配置通知类型
在这里插入图片描述
抽取切点表达式
在这里插入图片描述

在xml中配置组件扫描器和Aop的自动代理
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值