(三)Spring AOP_Spring_学习笔记

一、AOP 切面编程介绍

在软件业,面向切面编程,是指通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP(面向对象编程)的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容。
利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

AOP的特点:
AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码。
Spring AOP使用纯Java实现,不需要专门的编译过程和类加载器,在运行期通过代理方式向目标类织入增强代码。

经典应用:
事务管理、性能监视、安全检查、缓存 、日志等
这些系统服务通常被称为横切关注点。
想象一下如果每个组件都单独去实现这些系统功能:
改变这些关注点的逻辑,修改各个模块当中的实现,方法的调用就会重复出现在各个模块中,组件会因为那些与自身核心业务无关的代码而变得混乱。

未建立切面
在这里插入图片描述
建立切面
在这里插入图片描述
对比
在这里插入图片描述
AOP编程术语
在这里插入图片描述
理解
在这里插入图片描述

二、AOP实战

1.建立切面
aop底层将采用代理机制进行实现。
动态代理的两种机制
A:
接口 + 实现类 :spring采用 jdk 的动态代理Proxy。
怎么做的?基于接口去实现。
缺点:如果目标类没有实现任何接口呢?jkd动态代理就无能为力。
B:
实现类:spring 采用 cglib字节码增强。
怎么做的?基于继承。也可以实现动态代理。

3.AOP实现的三种方式

  1. 手动方式(自己实现)
    JDK动态代理
    CGLib动态代理
  2. 半自动方式(SpringAOP了解),需要手动一个一个地根据委托类生成代理对象。
  3. 自动方式(AspectJ掌握),AspectJ帮助我们批量生成由委托类生成的代理对象。

2.1半自动方式SpringAOP

2.1.1.配置环境

在pom.xml中引入依赖

	<dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.8.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.2.8.RELEASE</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

在这里插入图片描述

2.1.2.代码实现

接口和实现类

public interface UserService {
    public void sayHello();
}

@Service
public class UserServiceImpl implements UserService{
    @Override
    public void sayHello() {
        System.out.println("hello qyt");
    }
}

CustomInterceptor

@Component
public class CustomInterceptor implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
        System.out.println("有人说你野心勃勃");
        Object proceed = methodInvocation.proceed();
        System.out.println("有人爱你灵魂有火");
        return proceed;
    }
}

application.xml

 <context:component-scan base-package="com.qyt"/>
    <bean id="userServiceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
        <!--target:委托类-->
        <property name="target" ref="userServiceImpl"/>
        <!--interceptor组件的id,set接收的是字符串,这里写的是value属性-->
        <property name="interceptorNames" value="customInterceptor"/>
    </bean>
2.1.3.单元测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:application.xml")
public class SpringAopTest {
    /*//写法一
    @Autowired
    @Qualifier("userServiceProxy")
    UserService userService;*/

    /*//写法二
    @Resource(name = "userServiceProxy")
    UserService userService;*/

    //写法三
    @Autowired
    UserService userServiceProxy;
    @Test
    public void mytest1(){
        userServiceProxy.sayHello();
    }
}

在这里插入图片描述

2.1.4.这种方式的不足之处

每一个组件都需要单独使用ProxyFactoryBean生成代理组件,并且每次取出需要指定组件id。

2.2 自动方式AspectJ

AspectJ是什么?
AspectJ是基于java语言的AOP框架。
Spring2.0之后支持了基于AspectJ的切入点表达式的支持。
AspectJ扩展了Java语言,提供了一个专门的编译器,在编译时提供横向代码的织入
允许直接在class里面定义切面类。
主要用途,不改动现有代码的前提下,自定义开发。植入代码。
更侧重于指定方法 → 更侧重于划分方法的增强范围。

2.2.1.准备:引入依赖aspectjweaver

在这里插入图片描述

2.2.2 准备:application配置文件的aop标签

aop标签的获取:
1、使用已有的 2、去appendix找到 3、创建模板 4、自己改造
在这里插入图片描述
aop标签的使用:
切入点表达式
execution(修饰符 返回值 包名.类名.方法名(形参))
分析角度:
1、能否省略
2、能否通配
3、特殊用法

  • 修饰符
    可以省略不写 → 省略表示任意修饰符,一种特殊表达

  • 返回值
    不能省略
    可以使用 * 来通配
    如果是基本类型、包装类、java.lang目录下的类,可以直接写,javabean这些要写全类名,比如com.xxx.bean.User

  • 包名\类名\方法名
    可以部分省略:除了头和尾的部分不能省略,中间的任意一部分都可以省略 → 使用…来省略
    可以使用*来通配:可以表达一个层级或一个层级的一部分

  • 形参
    可以省略:表示无参方法
    能否通配:
    可以使用 * 来通配,一个 * 代表的是单个任意参数
    多个参数使用多个 * ,逗号分隔
    可以使用…代表任意数量的任意类型的参数
    特殊用法:和返回值类似,javabean要写全类名

  • 代码

    <aop:config>
        <!--id是一个标识,expression写的是切入点表达式,通过切入点表达式指定增强范围-->
        <!--修饰符:可以省略不写代表任意修饰符-->
        <!--返回值:不能省略,可以使用*通配,javabean要写全类名-->
        <!--包名、类名、方法名:部分省略,头和尾不能省略,中间部分都可以使用..来省略-->
        <aop:pointcut id="customPointcut1" expression="execution(public void com.cskaoyan.service.UserServiceImpl.say*())"/>
        <!--中间的任意一部分都可以省略掉-->
        <aop:pointcut id="customPointcut2" expression="execution(* com..say*())"/>
        <aop:pointcut id="customPointcut3" expression="execution(* com..service..say*())"/>
        <!--可以使用*通配一个层级或一个层级的一部分-->
        <aop:pointcut id="customPointcut4" expression="execution(public void *.cskaoyan.service.UserServiceImpl.say*())"/>
        <!--返回值:省略不写代表无参方法,使用*来通配单个任意类型的参数-->
        <aop:pointcut id="customPointcut5" expression="execution(public void *.cskaoyan.service.UserServiceImpl.say*(*))"/>
        <!--多个参数可以使用*,*,或者指定为对应类型-->
        <aop:pointcut id="customPointcut6" expression="execution(public void *.cskaoyan.service.UserServiceImpl.say*(String,Integer))"/>
        <!--使用..代表任意数量的任意类型的参数-->
        <aop:pointcut id="customPointcut7" expression="execution(public void *.cskaoyan.service.UserServiceImpl.say*(..))"/>
        <!--javabean要写全类名-->
        <aop:pointcut id="customPointcut8" expression="execution(public void *.cskaoyan.service.UserServiceImpl.say*(com.cskaoyan.bean.User,String))"/>

        <!--如果我们想要对service层的全部方法都做增强-->
        <aop:pointcut id="servicePointcut" expression="execution(* com..service..*(..))"/>
    </aop:config>
2.2.3 advisor(AspectJ实现方式一)

自定义通知通过实现接口,implements MethodInterceptor。
4.1.自定义通知

@Component
public class CustomInterceptor implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
        System.out.println("有人说你野心勃勃");
        Object proceed = methodInvocation.proceed();
        System.out.println("有人爱你灵魂有火");
        return proceed;
    }
}

4.2.advisor配置

	<aop:config>
        <!--id是一个标识,expression写的是切入点表达式,通过切入点表达式指定增强范围-->
        <aop:pointcut id="customPointcut" expression="execution(public void com.cskaoyan.service.UserServiceImpl.say*())"/>
        <!--advice-ref引用容器中的通知组件的id-->
        <!--pointcut → advisor自己来写切入点表达式-->
        <!--pointcut-ref → 引用配置过的aop:pointcut的对应id的切入点表达式-->
        <aop:advisor advice-ref="customInterceptor" pointcut-ref="customPointcut"/>
    </aop:config>

4.3.单元测试
接口和实现类

public interface UserService {
    public void sayHello();

    public void sayGoodbye();
}


@Service
public class UserServiceImpl implements UserService{
    @Override
    public void sayHello() {
        System.out.println("hello qyt");
    }

    @Override
    public void sayGoodbye() {
        System.out.println("再见了");
    }
}

单元测试

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:application.xml")
public class MyTest {
    @Autowired
    UserService userService;

    @Test
    public void mytest1(){
        userService.sayHello();
    }
    @Test
    public void mytest2(){
        userService.sayGoodbye();
    }
}

在这里插入图片描述

2.2.4 aspect(AspectJ实现方式二)

提供一些定义好的通知 → 相对于委托类的方法的时间不同
5.1.通知
在这里插入图片描述
5.2.定义切面类
5.2.1.joinPoint
在这里插入图片描述
5.2.2.通知
5.2.2.1.before
在这里插入图片描述
5.2.2.2.after
在这里插入图片描述
5.2.2.3.around
在这里插入图片描述
5.2.2.4.after-returning
在这里插入图片描述
5.2.2.5.after-throwing
在这里插入图片描述
在这里插入图片描述

5.3.使用注解的形式来使用aspectj
在这里插入图片描述
5.3.1.打开注解开关
在这里插入图片描述
5.3.2.切面类组件
5.3.2.1.定义为切面类
在这里插入图片描述
5.3.2.2.定义切入点表达式
方法的形式存在 →
表达id:方法名
表达expression:@Pointcut注解的value
方法体和形参里不需要写内容
在这里插入图片描述
5.3.2.3.通知方法
在这里插入图片描述
在这里插入图片描述
5.4.使用自定义的注解指定增强方法
Pointcut → 之前使用表达式指定增强方法 → 现在改为自定义注解
想要计算方法的执行时间 → 自定义注解加在哪一个方法上,哪一个就计算时间
5.4.1.自定义注解
在这里插入图片描述
5.4.2.Pointcut中使用自定义注解
在这里插入图片描述
在这里插入图片描述
5.5.小结
是否是所有的通知,都使用呢? 具体的业务使用具体的通知。
顺序:关注的是每个通知和委托类方法之间的顺序。
方法:切入点 → 指定增强方法 → 容器中组件中的方法。

三、JDBCTemplate

JDBCTemplate
Spring提供的用于操作jdbc的工具类。类似于JdbcUtils. 是对操作数据库的语句进行模板化的封装,让开发者只关注于数据库的sql语句即可。
JDBCTemplate也要依赖于数据源。

1.导包
在这里插入图片描述
2.se代码使用JdbcTemplate
在这里插入图片描述
3.Spring整合
spring-context
spring-test
在这里插入图片描述
4.补充一个autowired注解的使用
加载方法上 → 在实例的实例化过程中会调用到该方法

JdbcDaoSupport的拓展
在这里插入图片描述
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值