16-Spring 基于注解的AOP编程、AOP总结

上一篇:15-Spring AOP的底层实现原理JDKProxy&CGLIB https://blog.csdn.net/fsjwin/article/details/109481104

前面我们介绍的aop编程完全可以满足项目的需要,但是有没有更为简便的方式呢?
当然有了,就是aspectJ为我们提供的大餐,使用注解的aop编程
下面就开启我们的大仓之旅

值得注意的是不管是aop的注解编程,还是在xml中就行配置,他们的主要矛盾是一样的,矛盾的主要方面也是一样的。即

  1. 目标对象
  2. 增强功能
  3. 切入点
  4. 编制切面(切入点和增强功能整合在一起)

1.开发过程

  1. MyAspctJ .java 切面类(包含了增强功能、切入点、编制切面)
package aspectJ;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

/**
 * @author yuhl
 * @Date 2020/11/4 6:52
 * @Classname MyAspctJ
 * @Description 通过注解的方式aop开发
 * 但是这四样一样不能少
 * 1. 目标对象 UserServiceImpl
 * 2. 增强功能
 * 3. 切入点
 * 4. 编制切面(切入点和增强功能整合在一起)
 */

@Aspect //@Aspect告诉spring我是一个切面类
public class MyAspctJ {

    //1. 目标对象 UserServiceImpl
    UserService userService = new UserServiceImpl();

    /**
     * 切面, 内含2. 增强功能 和 3. 切入点
     *  2. 增强功能
     *  3. 切入点
     *  4. 编制切面(切入点和增强功能整合在一起)
     */
    @Around("execution(* login(..))") //3. 切入点
    public Object around(ProceedingJoinPoint proceedingJoinPoint){
        Object res = null;
        try {
            System.out.println("MyAspctJ.around 前**********" ); //2. 增强功能
            res = proceedingJoinPoint.proceed();
            System.out.println("MyAspctJ.around 后**********" ); //2. 增强功能
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        return res;

    }
}

  1. 配置文件,主要不是0配置哦!
<?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:p="http://www.springframework.org/schema/p"
       xmlns:context="http://www.springframework.org/schema/context"
       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/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">

    <bean id="userService" class="aspectJ.UserServiceImpl"/>
    <!--注解的aop编程 这个MyAspctJ还是要告诉spirng的-->
    <bean id="aspectj" class="aspectJ.MyAspctJ"/>
    <!--告诉spring开始注解的aop编程-->
    <aop:aspectj-autoproxy/>


</beans>
  1. 测试
    /**
     * 基于主机的aop编程
     */
    @Test
    public void test6() {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("/applicationContext8.xml");
        aspectJ.UserService userService = (aspectJ.UserService)ctx.getBean("userService");
        userService.login("zhangsan","111111");
        userService.register(new User(2, "222222"));
    }
  1. 结果
MyAspctJ.around 前**********
UserServiceImpl.login
MyAspctJ.around 后**********
UserServiceImpl.register
  1. 总结
    还是4个核心组件,一个不少,最终达到了想要的效果。这就是aspectj这个封装框架的强大之处。

  2. 进价
    想想一下,如果我的切面中有n多的方法均要使用这个切面怎办,如下:
    在这里插入图片描述

有没有看到代码冗余呢?有的。如果我们有999999个方法,那么这99999个方法的上面均要写上

  @Around("execution(* login(..))") //3. 切入点

那还不翻天了。有一天我们要修改这个切入点,要修改的黄花菜都凉了,怎么办。
对我们可以把他声明在一个地方,其他想用他的地方去引用不就好了。
看下面:
在这里插入图片描述
这样就完美解决这个问题。
具体代码入下:

import base.comobjectcreate.factorybean.MyConnectionFacoryBean;
import base.domain.*;
import base.factory.BeanFactory;
import base.lifecycle.Product;
import base.service.impl.UserServiceImpl;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import proxy.service.OrderService;
import proxy.service.User;
import proxy.service.UserService;

import java.sql.Connection;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;


/**
 * @author yuhl
 * @Date 2020/10/31 14:05
 * @Classname TestDemo
 * @Description TODO
 */
public class TestDemo2 {
    /**
     * 静态代理
     */
    @Test
    public void test1() {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("/applicationContext5.xml");
        UserService userService = (UserService)ctx.getBean("userService");
        userService.login("zhangsan","111111");
        userService.regester(new User(2, "222222"));
    }

    @Test
    public void test2() {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("/applicationContext5.xml");
        OrderService orderService = (OrderService)ctx.getBean("orderService");
        orderService.order();
    }

    /**
     * spring动态代理
     */
    @Test
    public void test3() {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("/applicationContext6.xml");
        OrderService orderService = (OrderService)ctx.getBean("orderService");
        orderService.order();
    }

    @Test
    public void test4() {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("/applicationContext6.xml");
        UserService userService = (UserService)ctx.getBean("userService");
        userService.login("zhangsan","111111");
        userService.regester(new User(2, "222222"));
    }

    @Test
    public void test5() {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("/applicationContext7.xml");
        proxy.service.UserService userService = (proxy.service.UserService)ctx.getBean("userService");
        userService.login("zhangsan","111111");
        userService.regester(new User(2, "222222"));
    }

    /**
     * 基于主机的aop编程
     */
    @Test
    public void test6() {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("/applicationContext8.xml");
        aspectJ.UserService userService = (aspectJ.UserService)ctx.getBean("userService");
        userService.login("zhangsan","111111");
        userService.register(new User(2, "222222"));
    }
}

测试结果

MyAspctJ.around 前**********
MyAspctJ.logAround 前**********
UserServiceImpl.login
MyAspctJ.logAround 后**********
MyAspctJ.around 后**********
UserServiceImpl.register

测试通过
7. jdkProxy和cgLib怎么选
默认情况下使用的是jdkproxy,证据如下。
在这里插入图片描述
如何切换默认使用cglib呢?

  • 在注解aop开发中切换十分简单:
<!--告诉spring开始注解的aop编程-->
    <aop:aspectj-autoproxy proxy-target-class="true"/>

添加proxy-target-class="true"即可,结果如下:
在这里插入图片描述

  • 如果使用之前的xml进行aop的开发怎么切换呢?想先也知道也是一个配置的事,但是写在哪里呢?
    配置如下:
    在这里插入图片描述
    也是这句话,只是放在了aop:config标签中:
    <aop:config proxy-target-class="true">

2.AOP编程的坑

可以参考:Spring中同一类@Transactional修饰方法相互调用的坑https://blog.csdn.net/fsjwin/article/details/109211355
userService中register()方法调用login()方法的时候,只调用哪个的是this.login()并不是userServiceProxy的login()方法。

  1. 问题现象
    在这里插入图片描述
    测试:
  /**
     * 基于主机的aop编程
     */
    @Test
    public void test6() {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("/applicationContext8.xml");
        aspectJ.UserService userService = (aspectJ.UserService)ctx.getBean("userService");
        //userService.login("zhangsan","111111");
        userService.register(new User(2, "222222"));
    }

运行结果:

UserServiceImpl.register
UserServiceImpl.login

这并不是我们想要的哦!我们想要的是能够对login()方法增强。
2. 问题解决
在这里插入图片描述
通过以上四部可以获得工厂,然后通过工厂再次获得代理对象,使用代理对象对login()方法进行调用即可。
UserServiceImpl.java

package aspectJ;

import base.dao.UserDao;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import proxy.service.User;

/**
 * @author yuhl
 * @Date 2020/10/31 14:07
 * @Classname userServiceImpl
 * @Description TODO
 */
public class UserServiceImpl implements UserService, ApplicationContextAware {

        ApplicationContext ctx = null;//获取项目启动的时候创建的那个工厂,从工厂中获得代理即可。

    @Override
    public boolean login(String username, String password) {
        System.out.println("UserServiceImpl.login");
        return true;
    }

    @Override
    public void register(User user) {
        System.out.println("UserServiceImpl.register");
        UserService userService = (UserService) ctx.getBean("userService");
        userService.login("于红亮", "ioewrioew");
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.ctx = applicationContext;
    }
}

结果:

UserServiceImpl.register
MyAspctJ.around 前**********
MyAspctJ.logAround 前**********
UserServiceImpl.login
MyAspctJ.logAround 后**********
MyAspctJ.around 后**********

3.AOP总结

一图在手,总结所有:
在这里插入图片描述
下一篇:17-Spring持久层框架整合https://blog.csdn.net/fsjwin/article/details/109485779

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值