springAOP面向切面思想

springAOP面向切面思想

spring 三大思想
IOC 控制反转
DI 依赖注入
AOP( Aspect Oriented Programming) 面向切面编程 弥补面向对象的不足

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

这样做的好处是:

  1. 在程序运行期间,在不修改源码的情况下对方法进行功能增强
  2. 逻辑清晰,开发核心业务的时候,不必关注增强业务的代码
  3. 减少重复代码,提高开发效率,便于后期维护

AOP相关概念

Target(目标对象):代理的目标对象
Proxy (代理):一个类被 AOP 织入增强后,就产生一个结果代理类
Joinpoint(连接点):所谓连接点是指那些被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方 法类型的连接点
Pointcut(切入点):所谓切入点是指我们要对哪些 Joinpoint 进行拦截的定义
Advice(通知/ 增强):所谓通知是指拦截到 Joinpoint 之后所要做的事情就是通知 分类:前置通知、后置通知、异常通知、最终通知、环绕通知
Aspect(切面):是切入点和通知(引介)的结合
Weaving(织入):是指把增强应用到目标对象来创建新的代理对象的过程。spring采用动态代理织入,而AspectJ采 用编译期织入和类装载期织入

OOP 面向对象编程 对象 类
先通过代码进行简单的了解一下aop

创建一个maven项目

实现:通过controller层调用service层然后调用dao层的方法
创建一个maven项目,导包(注意:把junit包的版本改为4.12以上),
创建一个包的层级,然后运行看看是否能走的通。
在resources下创建applicationContext.xml配置文件
比如创建一个bean类在pojo包

package com.lanou.pojo;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component(value = "user")
public class User {
    @Value(value = "123")
    private int id;
    @Value("张三丰")
    private String username;
    @Value("123456")
    private String password;
	//setter getter 有参 无参 toString方法
}

比如dao层
接口

import com.lanou.pojo.User;
import java.util.List;

public interface UserDao {
    List<User> findAll();
    User findUserById(int id);
    int updateUser(User user);
    int deleteUser(int id);
}

实现类


import com.lanou.dao.UserDao;
import com.lanou.pojo.User;
import org.springframework.stereotype.Repository;

import java.util.List;
@Repository(value = "userDao")
public class UserDaoImpl implements UserDao {
    @Override
    public List<User> findAll() {
        System.out.println("---------dao findAll 执行了--------");
        return null;
    }
    @Override
    public User findUserById(int id) {
        return null;
    }
    @Override
    public int updateUser(User user) {
        return 0;
    }
    @Override
    public int deleteUser(int id) {
        return 0;
    }
}

比如service层


import com.lanou.pojo.User;

import java.util.List;

public interface UserService {
    List<User> findAll();
    User findUserById(int id);
    int updateUser(User user);
    int deleteUser(int id);
}

service实现类


import com.lanou.dao.UserDao;
import com.lanou.pojo.User;
import com.lanou.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;


import java.util.List;
@Service(value = "userService")
public class UserServiceImpl implements UserService {
    @Autowired
    @Qualifier(value = "userDao")
    private UserDao userDao;
    @Override
    public List<User> findAll() {
        return userDao.findAll();
    }

    @Override
    public User findUserById(int id) {
        return null;
    }

    @Override
    public int updateUser(User user) {
        return 0;
    }

    @Override
    public int deleteUser(int id) {
        return 0;
    }
}

比如:控制层



import com.lanou.pojo.User;
import com.lanou.service.Impl.UserServiceImpl;
import com.lanou.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;

import java.util.List;

@Controller(value = "userController")
public class UserController {
    @Autowired
    @Qualifier(value = "userService")
    private UserService userService;
    public void findAll(){
        System.out.println("开始执行当前方法之前");
        List<User> userList = userService.findAll();
        System.out.println("方法执行结束");
    }
}

测试类中:


import com.lanou.controller.UserController;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class TestSpringJUnit {
    @Autowired
    @Qualifier(value = "userController")
    private UserController userController;
    @Test
    public void findAll() {
        userController.findAll();
    }
}

走的通

基于xml文件的切面编程

使用aop需要导入的jar包

spring-aop
spring-aspects
aopalliance
aspectjweaver

在maven会自动导入依赖的jar包
所以只需要在maven库中找到spring-aspects,aopalliance这两个jar包就行了

<!--aop 面向切面编程需要的jar包-->
    <!--aop-->
    <!--aspects-->
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-aspects -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aspects</artifactId>
      <version>5.1.14.RELEASE</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/aopalliance/aopalliance -->
    <dependency>
      <groupId>aopalliance</groupId>
      <artifactId>aopalliance</artifactId>
      <version>1.0</version>
    </dependency>

在utils包中定义一个切面类

/*
日志切面类
 */

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

//声明当前类是一个切面类
public class LogAdvice {
    /*
    切面方法
    前置通知方法
     */
    public void before(){
        System.out.println("--前置通知----");
    }
    /*
    切面方法
    后置通知方法 不管是否异常都返回
     */
    public void after(){
        System.out.println("--后置通知----");
    }
    /*
    后置通知 如果异常不返回值
     */
    public void afterReturning(){
        System.out.println("---后置通知--无异常-");
    }
    /*
    后置通知 异常返回
     */
    public void afterException(){
        System.out.println("--后置通知--异常通知--");
    }
    /*
    环绕通知
     */
    public Object around(ProceedingJoinPoint point) throws Throwable {
        System.out.println("环绕通知--前置通知");
        Object object = point.proceed();//继续调用目标方法
        System.out.println("环绕通知--后置通知");
        return object;
    }

}

在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: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">

    <context:annotation-config></context:annotation-config>
    <context:component-scan base-package="com.lanou"></context:component-scan>
   
    <!--定义切面信息-->
<bean id="logAdvice" class="com.lanou.utils.LogAdvice2"></bean>
    <!--定义切入点-->
    <aop:config>
        <!--
        切入点
        id : 名称
        expression : 表达式 找到包、类、方法
        execution(* com.lanou.service.*.*(..))
        第一个*  方法的返回值类型
        com.lanou.service 包名
        第二个*  类名
        第三个*  方法名
        (..)  任意参数
        -->
        <aop:pointcut id="pc" expression="execution(* com.lanou.service.*.*(..))"/>
        <!--定义关联的切面-->
        <aop:aspect ref="logAdvice">
            <aop:before method="before" pointcut-ref="pc"></aop:before>
            <aop:after method="after" pointcut-ref="pc"></aop:after>
            <aop:after-returning method="afterReturning" pointcut-ref="pc"></aop:after-returning>
            <aop:after-throwing method="afterException" pointcut-ref="pc"></aop:after-throwing>
            <aop:around method="around" pointcut-ref="pc"/>
        </aop:aspect>
    </aop:config>
</beans>

在测试类中运行测试方法可以看到,在核心逻辑执行前执行前置通知,环绕通知。oop是感觉是纵向的,但是aop就像是横向的给你切开,加上你想要执行的增强业务(前置通知属于增强业务),在执行核心业务(dao findAll核心业务)之前执行前置业务
在这里插入图片描述

基于注解的AOP

在xml文件中开启注解
(注意:开启注解的时候把xml配置的给注释喽,因为我测试的时候,感觉xml配置的优先级高于注解的优先级)

	<!--开启aop注解-->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

在utils包中LogAdvice加上注解

/*
日志切面类
 */

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

@Component(value = "logAdvice")
//声明当前类是一个切面类
@Aspect
public class LogAdvice {
	/*
	如果表达式相同就不用再配置别的,
	可以这样加上@Pointcut("execution(* com.lanou.service.*.*(..))")
	注解让每次环绕的时候加入"LogAdvice.pc()"就不用每次都配置了
	*/
    @Pointcut("execution(* com.lanou.service.*.*(..))")
    public void pc(){

    }

    /*
    切面方法
    前置通知方法
    每次都要跟上一个表达式有没有一个方法,如果表达式相同就不用再配置的其他的
     */
    @Before("LogAdvice.pc()")
    public void before(){
        System.out.println("--前置通知----");
    }
    /*
    切面方法
    后置通知方法 不管是否异常都返回
    
     */
    @After("execution(* com.lanou.service.*.*(..))")
    public void after(){
        System.out.println("--后置通知----");
    }
    /*
    后置通知 如果异常不返回值
     */
    @AfterReturning("execution(* com.lanou.service.*.*(..))")
    public void afterReturning(){
        System.out.println("---后置通知--无异常-");
    }
    /*
    后置通知 异常返回
     */
    @AfterThrowing("execution(* com.lanou.service.*.*(..))")
    public void afterException(){
        System.out.println("--后置通知--异常通知--");
    }
    /*
    环绕通知
     */
    @Around("execution(* com.lanou.service.*.*(..))")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        System.out.println("环绕通知--前置通知");
        Object object = point.proceed();//继续调用目标方法
        System.out.println("环绕通知--后置通知");
        return object;
    }
}

调用测试方法:跟在xml中的配置是一个效果

AOP一些概念介绍

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值