ssm框架复习巩固

SSM框架复习第六天:动态代理  AOP(面向切面编程)

1.动态代理:动态代理技术,利用截取消息的方式,对该消息进行装饰,以取代原有对象行为的执行;二是采用静态织入的方式,引入特定的语法创建“方面”,从而使得编译器可以在编译期间织入有关“方面”的代码.

简单点解释,比方说你想在你的biz层所有类中都加上一个打印‘你好’的功能,这时就可以用aop思想来做.你先写个类写个类方法,方法经实现打印‘你好’,然后Ioc这个类 ref=“biz.*”让每个类都注入即可实现。

AOP底层的实现原理:使用动态代理增强对象

spring 实现AOP的时候底层的代理方式

1. jdk动态代理

2. CGLib动态代理

不同:
JDK:
1.目标类必须实现接口 JDK的动态代理是针对接口产生代理对象
2.目标类和代理类之间是(同级)兄弟关系,都会实现相同的接口
Cglib:
1.目标类不需要实现接口也能产生代理对象,cglib的动态代理是针对目标类产生代理对象
2.目标类和代理类之间是一种继承关系

 2.AOP

 AOP的概念

   AOP(面向切面编程)

   OOP(面向对象编程)

OOP : 专注于在业务开发过程中把各个抽象的东西封装成对象 (属性  行为)

AOP : 切面   面向对象编程的一种延续

AOP:是一种编程思想,和oop一样,可以说是oop的一种延伸。在传统编程写代码的时候,如果我们在在多个类中调用(当我们需要为分散的对象引入公共行为的时候)同一个方法(功能)的时候,可以能回导致重复的代码太多了,方法与方法(业务逻辑)之间存在严重耦合(例如日志功能。日志代码往往水平地散布在所有对象层次中,而与它所散布到的对象的核心功能毫无关系。在OOP设计中,它导致了大量代码的重复,而不利于各个模块的重用。)这个时候我们要把这个方法(功能)封装成一个封面,然后注入要所需要这个功能的类中。(利用spring的ioc的rel属性)将程序中的交叉业务逻辑(比如安全,日志,事务等),封装成一个切面,然后注入到目标对象(具体业务逻辑)中去。

 AOP解决什么问题

 AOP专注于把各个业务逻辑部分进行抽取,达到减低各个业务逻辑部分之间耦合度的目的

 两个方法产生了关联(联系)

方法与方法之间的耦合 一个方法(业务)的改变会影响另一个方法的改变
就是解决方法(业务逻辑)与方法(业务逻辑)的耦合

传统代码开发存在的问题

  1. 重复代码太多

  2. 方法与方法(业务逻辑与业务逻辑)之间存在耦合

3.Spring的AOP的开发

1. xml配置

1.导入依赖

 

  <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.0.2.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.8.7</version>
    </dependency>

2.在业务层创建接口和实现类

package com.swlz.service;

/**
 * 定义了对用户进行增删改查的方法
 */
public interface IUserService {
    public void findAll();
    public void saveUser(String user);
    public void updateUser();
    public void deleteUser();
}
package com.swlz.service.impl;
import com.swlz.service.IUserService;

/**
 * 用户基本增删改查的业务代码
 */
public class UserServiceImpl implements IUserService {
    public void findAll() {
        System.out.println("UserServiceImpl 调用Dao查询所有用户");
    }
    public void saveUser(String user) {
        System.out.println("UserServiceImpl 调用Dao保存用户" + user);
    }
    public void updateUser() {

        System.out.println("UserServiceImpl 调用Dao更新用户");
    }
    public void deleteUser() {

        System.out.println("UserServiceImpl 调用Dao删除用户");
    }
}

3.创建日志类(增强的方法)

public class LogUtils {
 public void printLog(){
System.out.println("记录日志.....////");
}

// 方法执行之前
public void beforeLog(){
System.out.println("记录日志 ...beforeLog");
}
// 方法执行之后
public void afterReturingLog(){
System.out.println("记录日志 ...afterReturingLog");
}
// 方法出现异常的时候
public void afterThrowingLog(){
System.out.println("记录日志 ...afterThrowingLog");
}
// 所有方法执行完之后,也就是最终
public void afterLog(){
System.out.println("记录日志 ...afterLog");
}
}

4.在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="userService" class="com.swlz.service.impl.UserServiceImpl"></bean>
    <bean id="accountService" class="com.swlz.service.impl.AccountServiceImpl"></bean>
    <!--Spring  Aop 配置-->
    <!--第一步 配置通知类对象 -->
<bean id="logAdvice" class="com.swlz.log.LogUtils"></bean>
<!--配置aop-->
    <!--第二步  开启AOP配置(完成自动代理)-->
    <aop:config>
<!--        切点表达式   id="pc"-->
        <aop:pointcut id="pc" expression="execution(* com.swlz.service..*(..))"></aop:pointcut>
<!--配置切面-->
        <aop:aspect ref="logAdvice">
            <!--定义通知和通知中指定切点   切点定义方式(AspectJ框架提供):通过切点表达式-->
<!--            <aop:before method="printLog" pointcut="execution(public void com.swlz.service.impl.UserServiceImpl.findAll())"></aop:before>-->
            <!--切点定义方式(AspectJ框架提供):通过切点表达式

           1. 完整写法
             public       void      com.bianyiit.service.impl.UserServiceImpl.saveUser(String)
           方法访问修饰符  返回值      包名                       类名            方法名  方法参数

           2. 方法访问修饰符可以被省略
                void      com.bianyiit.service.impl.UserServiceImpl.saveUser(String)
               返回值      包名                       类名            方法名  方法参数

           3 . 方法返回值类型可以用  * 号代替
                *      com.bianyiit.service.impl.UserServiceImpl.saveUser(String)
               返回值      包名                       类名            方法名  方法参数

           4 . 包名和类名可以省略
                     * save*(..))
               返回值       方法名  方法参数

          5 . 整个表达式中只有   方法返回值类型    方法名   方法参数不能省略,其他都能省略
                   其中  方法返回类型  和方法名可以使用*号通配, 方法参数可以使用..通配
                   方法名   save*     以save开头的方法
                     * *(..))
               返回值       方法名  方法参数
           -->
<!--            <aop:before method="printLog" pointcut="execution(* save*(..))"></aop:before>-->
<!--   pointcut="execution(* com.swlz.service..*(..)) 切点表达式 表示service层中的所有类中所有的方法-->
            <aop:before method="printLog" pointcut-ref="pc"></aop:before>
            <!-- <aop:before method="beforeLog" pointcut-ref="pc"/>
<-方法执行之后   -->
            <aop:after-returning method="afterReturingLog" pointcut-ref="pc"></aop:after-returning>
<!--            <-方法出现异常的时候所要执行的方法 &ndash;&gt;-->
            <aop:after-throwing method="afterThrowingLog" pointcut-ref="pc"></aop:after-throwing>
<!--            <-所有方法执行完之后,也就是最终&ndash;&gt;-->
            <aop:after method="afterLog" pointcut-ref="pc"></aop:after>
        </aop:aspect>
    </aop:config>
</beans>
4.四张基本通知(具体增强的功能(方法))类型基于xml配置的时候基本的执行顺序
前置通知--目标方法---后置通知----最终通知
前置通知--目标方法---异常通知----最终通知
注意:如果出现了异常就不会执行后置通知

切面:切点+通知

切点:需要对目标中那些方法进行增强的定义
advice(通知):具体增强的功能(方法)
连接点(joinPoint):所有有可能被增强的方法
今日学习感受:唯有坚持才会不负你所热爱的,有些东西需要你自己正在的去尝试并且坚持下去,它会在无形中可能会给你带来意外的惊喜。最后一句话:我心光明,心向光明,心之所向,必能所往!

posted @ 2021-12-26 23:47  编程玩家1号  阅读(32)  评论(0)    收藏  举报