AOP动态代理之CGlib注解版-很详细

AOP:面向切面编程.指的是将项目中的切面(横切逻辑)单独抽离出来,进行统一编程处理.

  • 1:切面:一些零散的,散落在系统各处,不得不处理,但是又与核心业务无关横切逻辑叫切面. eg:异常,日志,事务

  • 2:面向对象编程(OOP)主要作用:是处理核心业务逻辑,面向切面编程(AOP)主要作用是处理切面横切逻辑).面向切面编程是面向对象编程的有益补充,或者说是面向对象辅助.

  • 3:面向切面编程底层用的就是动态代理模式.

  • 4:面向切面编程目地:让程序员专注写业务.

代理模式:代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。通俗的来讲代理模式就是我们生活中常见的中介。
作用:保护原对象,增加原对象的功能.
动态代理:是在程序运行时通过反射机制动态创建的。两种方式:jdk实现动态代理 和 CGLib实现动态代理
jdk实现动态代理:必须依赖原对象的父接口
CGLib实现动态代理:GCLib采用底层的字节码技术,可以为一个类创建子类,在子类中采用方法拦截的技术拦截所有父类方法的调用并 顺势织入横切逻辑.

**

进入正题:AOP动态代理之CGlib注解版实现

**
1.创建maven工程(过程不啰嗦~)
2.pom.xml配置相关依赖包(不必要的可以删掉)

<dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>5.1.3.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>5.1.3.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.1.3.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>5.1.3.RELEASE</version>
        </dependency>
        <!--注解版相关包-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>5.1.3.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-expression</artifactId>
            <version>5.1.3.RELEASE</version>
        </dependency>
        <!--<dependency>-->
            <!--<groupId>org.springframework</groupId>-->
            <!--<artifactId>spring-orm</artifactId>-->
            <!--<version>5.1.3.RELEASE</version>-->
        <!--</dependency>-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>5.1.3.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.1.3.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.1.3.RELEASE</version>
        </dependency>
        <!-- 为了方便进行单元测试,添加spring-test包 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.1.3.RELEASE</version>
        </dependency>
        <!--日志包-->
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging-api</artifactId>
            <version>1.1</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.14</version>
        </dependency>
    </dependencies>

3.创建业务接口(嫌麻烦的可以省略,直接创建一个业务类)

package Demo1;

/**
 * 自我介绍的业务接口
 */
public interface peopleService {
    public void showMySelf();
}

4.业务接口实现类(类上使用注解)

package Demo1;

import org.springframework.stereotype.Component;

@Component("p1")//用@Service("p1")也可以
public class peopleServiceImpl implements peopleService {
    public void showMySelf() {
        System.out.println("自我介绍的方法");
//        int a = 8/0;
    }
}

5.创建增强类,并将切点与增强方法绑定(注意:类和方法上使用了注解),此处用打印日志模拟增强方法中的业务.(嫌麻烦 可以改成sout的打印语句)

package Demo1;

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

/**
 * 增强类 MyAdvice
 */
@Aspect
@Component//这个注解不能少
public class MyAdvice {
    public Logger log = Logger.getRootLogger();
	/*
    * xecution(* Demo1.*Impl.*(..)):表示切点 即:需要增强处理的方法
    * 此处表示Demo1包下面以Impl结尾的任一方法 方法参数为动态参数(其实就是为了匹配到目标方法 这里也可以直接写方法名)
    * */
    @Before("execution(* Demo1.*Impl.*(..))")
    public void before() {
        log.info("前置增强");
    }
    @AfterReturning("execution(* Demo1.*Impl.*(..))")
    public void afterReturn() {
        log.info("后置增强");
    }
    @AfterThrowing("execution(* Demo1.*Impl.*(..))")
    public void afterThrowing() {
        log.info("异常增强");
    }
    @After("execution(* Demo1.*Impl.*(..))")
    public void after() {
        log.info("最终增强");
    }
    @Around("execution(* Demo1.*Impl.*(..))")
    public Object around(ProceedingJoinPoint pj) throws Throwable {
        log.info("环绕增强前面");
        Object ob = pj.proceed();//调用切点的方法
        log.info("环绕增强后面");
        return ob;
    }
}

6.添加log4j日志文件到resources目录 其内容:

log4j.rootLogger=info,A1
log4j.logger.org.mybatis = info
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss,SSS} [%t] [%c]-[%p] %m%n

7.配置spring.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"
       xmlns:context="http://www.springframework.org/schema/context"
       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 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <!--指定扫描注解的包-->
    <context:component-scan base-package="Demo1"/>
    <!--开启aop扫描-->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
    <!--设置代理模式为CGlib-->
    <aop:config proxy-target-class="true"></aop:config>
</beans>

8.进行单元测试

package entity;

import Demo1.peopleService;
import Demo1.peopleServiceImpl;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * aop注解版
 */
public class TestPeopleSevrice {
    /**
     * 传统方法 业务对象调方法
     */
    @Test
    public void TestShowMySelf1(){
        peopleService p = new peopleServiceImpl();
        p.showMySelf();
    }
    /**
     * AOP注解版测试
     */
    @Test
    public void TestShowMySelf2(){
        ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
        peopleServiceImpl p1 = ac.getBean("p1", peopleServiceImpl.class);
        p1.showMySelf();
    }

}

执行注解版测试方法:
在这里插入图片描述
当程序异常(将业务实现类的该行代码取消注释:// int a = 8/0;)再次执行注解版测试方法 触发异常抛出增强:
在这里插入图片描述

通过看打印的日志,可以看出各个增强方法在相对于切点的调用时机.

附带本次项目结构的截图:
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值