AOP思想的学习以及实现

1.AOP:面向切面编程,通过预编译的方式和运行期动态代理实现程序功能的统一维护的一种技术。

2.AOP在Spring中的作用

  

3.SpringAOP中,我们使用Advice来定义横切逻辑,Spring中支持5种类型的Advice

  分别是:前置通知   MethodBeforeAdvice

      后置通知   AfterReturningAdvice

      环绕通知   MethodInterceptor

      异常抛出通知

      引介通知

4.使用AOP织入,需要倒一个maven包

<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.4</version>
    <scope>runtime</scope>
</dependency>

  实现AOP的两种方式:

  方法一:使用Spring的API接口  5大点

  方法二:使用自定义类  6大点

5.使用前置通知和后置通知实现代理日志的打印(方法一使用Spring的API接口)感觉有点反人类记不住啊

   5.1抽象对象

public interface UserService {
    public void add();
    public void delete();
    public void update();
    public void select();
}

  5.2实际对象

import org.springframework.stereotype.Component;
//使用了注解,注册到容器中,id是userServiceImpl
@Component
public class UserServiceImpl implements UserService{
    public void add() {
        System.out.println("增加了一个用户");
    }

    public void delete() {
        System.out.println("删除了一个用户");
    }

    public void update() {
        System.out.println("修改了一个用户");
    }

    public void select() {
        System.out.println("查询了一个用户");
    }
}

  5.3前置通知日志对象和后置通知日志对象

import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
//前置通知日志对象,使用了注解注册到Spring容器中,id第一个字母小写
@Component
public class BeforAdvicelog implements MethodBeforeAdvice {

    public void before(Method method, Object[] objects, Object o) throws Throwable {
        System.out.println("之前"+o.getClass().getName()+"调用了"+method.getName()+"的方法");
    }
}
import java.lang.reflect.Method;
//后置日志通知
@Component
public class AfterAdvicelog implements AfterReturningAdvice {
    public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
        System.out.println(""+"调用了"+method.getName()+"方法"+"结果是"+o);
    }
}

  5.4XML配置

    使用aop要注意添加  aop

      xmlns:aop="http://www.springframework.org/schema/aop"
      http://www.springframework.org/schema/aop
      https://www.springframework.org/schema/aop/spring-aop.xsd"

    使用注解要注意引入context  跟上面aop类似

      注意添加

      <context:annotation-config/>    //引入配置  
      <context:component-scan base-package="com.chen"/>  //使用注解的包

    使用SpringAPI实现AOP aop:config  下使用aop:pointcut 和aop:advisor

<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://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:component-scan base-package="com.chen"/>

    
    <aop:config>
        <!--先有切入点pointcut id="切入点的名字" expression="execution(要执行的位置! (*(修饰词) *(返回值) *(类名) *(方法名) *(参数)))"-->
        <aop:pointcut id="pointcut" expression="execution(public * com.chen.service.UserServiceImpl.*(..))"/>
        <!--有了切入点(哪个方法)就可以执行环绕了-->
        <!--下面这行就是引用哪个切入日志,在哪个切入点上-->
        <aop:advisor advice-ref="beforAdvicelog" pointcut-ref="pointcut"/>
        <aop:advisor advice-ref="afterAdvicelog" pointcut-ref="pointcut"/>

    </aop:config>
   
</beans>

    注意:

      execution(修饰符 返回值 包名.类名/接口名.方法名(参数列表))可以忽略掉修饰符了 自己可以写上修饰符(public等)
      (..)可以代表任意参数,(*)代表一个参数,(*,String)代表第一个参数为任何值,第二个参数为String类型

      <aop:pointcut id="pointcut" expression="execution(public * com.chen.service.UserServiceImpl.*(..))"/>
      意思是:返回公共的 任意返回值的 com.chen.service.UserServiceImpl 的所有方法,方法的参数是所有参数

  5.5测试代码以及执行结果

import com.chen.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Mytest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserService userserviceimpl = context.getBean("userServiceImpl", UserService.class);//代理的都是接口,所以要返回接口类型
        userserviceimpl.add();
    }
}

    

 6.使用自定义类实现AOP

  6.1首先先自定义一个类作为日志输出类(后续要作为切面) 

import org.springframework.stereotype.Component;

@Component
public class Diylog {
    public void beforelog(){
        System.out.println("======自定义日志执行前调用========");
    }
    public void afterlog(){
        System.out.println("======自定义日志执行后调用========");
    }
}

  6.2xml配置

  自定义类实现AOP要使用<aop:config> 下的<aop: aspect>

    <bean id="diylog" class="com.chen.DiyLog.Diylog"/>
    <aop:config>
        <aop:aspect id="qiemian" ref="diylog">   <!--自定义类要先有一个切面 ,切面就是这个自定义类-->
            <!--定义切点-->
            <aop:pointcut id="pointcut" expression="execution(public * com.chen.service.UserServiceImpl.*(..))"/>
            <!--在diylog这个切面上,在pointcut这个切点上,调用diylog类里面的before方法-->
            <aop:before method="beforelog" pointcut-ref="pointcut"/>
            <aop:after method="afterlog"  pointcut-ref="pointcut"/>
        </aop:aspect>
    </aop:config>

   

 6.3测试结果 

    

 

 

posted @ 2021-11-25 21:22  qwedfrgh  阅读(58)  评论(0)    收藏  举报