Spring07-AOP

Spring AOP

Spring AOP的基础是动态代理,因此学习AOP前需要了解相关的动态代理知识

什么是AOP?

AOP实际上就是面向切面,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。
一般来说,我们所写的代码都是一种纵向伸展的代码,例如UserDao->UserDaoImp->UserService->UserServiceImp,通过抽取共性,进行纵向的伸展
但是对于AOP而言,更多的是一种横向的插入,例如添加日志、事务提交等操作

在这里插入图片描述
举个例子
我们jdbc操作数据库需要经历一系列的操作
1.获取连接
2.执行sql
3.提交或回滚事务
4.关闭连接
在这里插入图片描述
但是实际上,我们最需要关系的只是执行sql,其他的都是可以横向抽取出来,这时候就可以用到AOP

AOP的一些术语

  1. 连接点(Joinpoint) 程序执行的某个特定位置,如某个方法调用前,调用后,方法抛出异常后,这些代码中的特定点称为连接点。简单来说,就是在哪加入你的逻辑增强
  2. 切点(PointCut) 每个程序的连接点有多个,如何定位到某个感兴趣的连接点,就需要通过切点来定位。比如,连接点–数据库的记录,切点–查询条件。切点用于来限定Spring-AOP启动的范围,通常我们采用表达式的方式来设置,所以关键词是范围
  3. 增强(Advice) 增强是织入到目标类连接点上的一段程序代码。在Spring中,像BeforeAdvice等还带有方位信息
    前置通知(before):在执行业务代码前做些操作,比如获取连接对象
    后置通知(after):在执行业务代码后做些操作,无论是否发生异常,它都会执行,比如关闭连接对象
    异常通知(afterThrowing):在执行业务代码后出现异常,需要做的操作,比如回滚事务
    返回通知(afterReturning),在执行业务代码后无异常,会执行的操作
    环绕通知(around),这个目前跟我们谈论的事务没有对应的操作,所以暂时不谈
    目标对象(Target) 需要被加强的业务对象
    织入(Weaving) 织入就是将增强添加到对目标类具体连接点上的过程。
    切面(Aspect) 切面由切点和增强组成,它既包括了横切逻辑的定义,也包括了连接点的定义,SpringAOP就是将切面所定义的横切逻辑织入到切面所制定的连接点中。
    比如上文讨论的数据库事务,这个数据库事务代码贯穿了我们的整个代码,我们就可以这个叫做切面。 SpringAOP将切面定义的内容织入到我们的代码中,从而实现前后的控制逻辑。 比如我们常写的拦截器Interceptor,这就是一个切面类

针对术语本人的理解
增强(Advice) 实际上就是你需要的功能,比如记录日志、安全、事务等
连接点(JoinPoint) 实际上就是允许使用通知的地方,比如方法前后,异常,返回,环绕
切点(PointCut) 我理解切点实际上就是一个范围,包含了多个连接点。比如一个类里有10个方法,那应该存在几十个连接点,但是我并非都需要在所有的连接点处织入通知,只是需要在其中的几个方法中织入通知,因此可使用切点定义范围。切点一般通过表达式来约束范围
切面 切面实际上就是切点和增强的结合
目标对象 可以理解为实际实现功能的类,也是真正的业务逻辑。它可以在毫不察觉的情况下被我们织入切面
**织入(Weaving)**将切面放入目标对象,形成新的代理对象的过程

Spring AOP入门

第一种

使用AOP需要先引入依赖
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.4</version>
        </dependency>

新建业务类UserService、UserServiceImp

public interface UserService {

    public void add();
    public void delete();
    public void update();
    public void query();
}
public class UserServiceImp implements UserService{
    @Override
    public void add() {
        System.out.println("add");
    }

    @Override
    public void delete() {
        System.out.println("del");
    }

    @Override
    public void update() {
        System.out.println("update");
    }

    @Override
    public void query() {
        System.out.println("query");
    }
}

新建BeforeLog类,实现MethodBeforeAdvice接口,重写before方法

public class BeforeLog implements MethodBeforeAdvice {
    /*
        method : 要执行的目标对象方法
        args :  方法参数
        target: 目标对象
     */
    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println(target.getClass().getName()+"的方法"+method.getName()+"执行了");
    }
}

新建AfterLog类,实现AfterReturningAdvice

public class AfterLog implements AfterReturningAdvice {
    @Override
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
        System.out.println(target.getClass().getName()+"的方法"+method.getName()+"执行了");
    }
}

配置xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       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="beforeLog" class="com.jojo.BeforeLog"></bean>
    <bean id="afterLog" class="com.jojo.AfterLog"></bean>
    <bean id="userService" class="com.jojo.UserServiceImp"></bean>

    <aop:config>
        <aop:pointcut id="pointcut" expression="execution(* com.jojo.UserServiceImp.*(..))"/>
        <aop:advisor advice-ref="beforeLog" pointcut-ref="pointcut"></aop:advisor>
        <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"></aop:advisor>
    </aop:config>
</beans>

xml中的aop-config是aop的配置,其中可配置切入点、通知,组成切面织入目标类

执行测试,并输出结果

public class Test {

    @org.junit.Test
    public void test(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
        UserService userService = (UserService) applicationContext.getBean("userService",UserService.class);
        userService.add();
        userService.delete();
    }
}

输出:
com.jojo.UserServiceImp的方法add执行了
add
com.jojo.UserServiceImp的方法add执行了
com.jojo.UserServiceImp的方法delete执行了
del
com.jojo.UserServiceImp的方法delete执行了

第二种
自定义类来实现AOP

新建增强类MyPointCut

public class MyPointCut {

    public void before(){
        System.out.println("方法执行前");
    }

    public void after(){
        System.out.println("方法执行后");
    }
}

修改配置文件

<bean id="userService" class="com.jojo.UserServiceImp"></bean>
<bean id="myPointCut" class="com.jojo.MyPointCut"></bean>

<aop:config>
        <aop:aspect ref="myPointCut">
            <aop:pointcut id="pointcut" expression="execution(* com.jojo.UserServiceImp.*(..))"/>
            <aop:before method="before" pointcut-ref="pointcut"></aop:before>
            <aop:after method="after" pointcut-ref="pointcut"></aop:after>
        </aop:aspect>
    </aop:config>

进行测试并输出结果

public class Test {

    @org.junit.Test
    public void test(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
        UserService userService = (UserService) applicationContext.getBean("userService",UserService.class);
        userService.add();
        userService.delete();
    }
}

输出:
方法执行前
add
方法执行后
方法执行前
del
方法执行后

第三种
使用注解实现AOP
新建一个增强类MyPointCut2

@Aspect
public class MyPointCut2 {
    @Before("execution(* com.jojo.UserServiceImp.*(..))")
    public void before(){
        System.out.println("方法执行前");
    }

    @After("execution(* com.jojo.UserServiceImp.*(..))")
    public void after(){
        System.out.println("方法执行后");
    }

}
//注意,需要加上@Aspect注解,声明切面

配置xml文件

 <bean id="myPointCut2" class="com.jojo.MyPointCut2"></bean>

    <aop:aspectj-autoproxy>
    </aop:aspectj-autoproxy>

进行测试

public class Test {

  @org.junit.Test
  public void test(){
      ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
      UserService userService = (UserService) applicationContext.getBean("userService",UserService.class);
      userService.add();
      userService.delete();
  }
}

输出:
方法执行前
add
方法执行后
方法执行前
del
方法执行后
通过aop命名空间的<aop:aspectj-autoproxy />声明自动为spring容器中那些配置@aspectJ切面的bean创建代理,织入切面。当然,spring 在内部依旧采用AnnotationAwareAspectJAutoProxyCreator进行自动代理的创建工作,但具体实现的细节已经被<aop:aspectj-autoproxy />隐藏起来了

<aop:aspectj-autoproxy />有一个proxy-target-class属性,默认为false,表示使用jdk动态代理织入增强,当配为<aop:aspectj-autoproxy  poxy-target-class="true"/>时,表示使用CGLib动态代理技术织入增强。不过即使proxy-target-class设置为false,如果目标类没有声明接口,则spring将自动使用CGLib动态代理。

<aop:aspectj-autoproxy />会织入所有@Aspect标记的切面

再新建一个增强类MyPointCut3
@Aspect
public class MyPointCut3 {

    @Before("execution(* com.jojo.UserServiceImp.*(..))")
    public void before(){
        System.out.println("方法执行前3");
    }

    @After("execution(* com.jojo.UserServiceImp.*(..))")
    public void after(){
        System.out.println("方法执行后3");
    }
}
配置xml
 <bean id="myPointCut3" class="com.jojo.MyPointCut3"></bean>

进行测试

public class Test {

   @org.junit.Test
   public void test(){
       ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
       UserService userService = (UserService) applicationContext.getBean("userService",UserService.class);
       userService.add();
       userService.delete();
   }
}

输出:
方法执行前
方法执行前3
add
方法执行后3
方法执行后
方法执行前
方法执行前3
del
方法执行后3
方法执行后
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值