SpringAop的三种配置方法:基于ProxyFactoryBean、基于AspectJ的xml,基于AspectJ的注解

面向切面编程,是面向对象编程的一中拓展,将各个对象中的同级共性代码块提取出来进行方法封装。解耦,使得代码更加的简洁高效;其底层应用的原理是动态代理。可以增强方法,书写日志。

Springxml头部声明:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       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">
   
    

</beans>

 

     

 

 

简单来说,连接点,就是程序执行过程中的各个阶段点。切点就是我们需要处理的地方,一般是方法。

切面就是我们的增强方法和业务逻辑。

基于ProxyFactoryBean的代理实现:

在ProxyFactoryBean的配置中,最重要的是两个点:切点和切面。

首先我们先在java中把对应的切面类配置好:这个类必须实现MethodInterceptor接口。具体为什么可以看动态代理的两种实现JDK和Cglib。

public class myaspect implements MethodInterceptor {
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {

        System.out.println("方法被调用");
        methodInvocation.proceed();

        return null;
    }
}

因为我们是基于Spring实现的Aop,所以在Spring的控制反转下,所有的实体都由Spring的容器创建,所以我们应该将切面加入容器中:

 <bean id="myaspect" class="com.aaa.aop.myaspect"></bean>

然后将我们需要代理的类也放在容器中:

<bean id="studentDao" class="com.aaa.Dao.StudentImpl"></bean>

之后就是要让代理的类和切面发生关系。

<bean  class="org.springframework.aop.framework.ProxyFactoryBean" id="factoryBean"  >
     <property name="target" ref="studentDao"></property>
      <property name="interceptorNames" value="myaspect"></property>


        <property   name="proxyTargetClass" value="true"></property>
    </bean>

为什么会有jdk和CGLIB两种选择?
1.jdk 只能代理类实现的接口的类,而没有实现接口类必须使用CGLIB
2.从性能来说:
CGLIB:创建慢,执行块
JDK:创建快,执行慢(反射本身执行就比正常代码的慢

从底层原理上来说:jdk动态代理实现的是创建一个实现被代理类的代理对象。而Cglib实现的是创建一个继承被代理类的代理对象。

之后我们就可以测试了。JDK (如果是想测试Cglib的话,需要将StudentDao换成他的实现类即可)。

 public static void main(String[] args) {
        ApplicationContext applicationContext=new ClassPathXmlApplicationContext("AAop.xml");
      // Cglib测试:
       // StudentImpl studentImpl=(StudentImpl) applicationContext.getBean("factoryBean");
        StudentDao studentDao= (StudentDao) applicationContext.getBean("factoryBean");
        studentDao.findStudent();
        


    }

分割线----------------------------------------------------------------------------------------------------------------------------------------------------------

基于AspectJ的AOP实现

1、基于xml的AspectJ

  切点表达式:切点表达式用来配置我们想要拦截哪些方法。

         格式:

     

切点表达式:
   public  void  com.aaa.Dao.StudentImpl.findStudent() throw
    权限     返回类型   类限定名              方法名    参数  异常
    省略      *      com.aaa.Dao.*.*(..)          
其中  * 代表全部,(。。) 代表参数不限。

配置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 https://www.springframework.org/schema/aop/spring-aop.xsd">
   <!-- 目标对象-->
    <bean id="studentDao" class="com.aaa.Dao.StudentImpl"></bean>

    <!--获取切面 -->
    <bean class="com.aaa.aop.AspectJ.xml.MyAspect" id="myAspect"></bean>
    <!--配置对应的关系  基于aspectj织入   -->
    <aop:config>
        <!--声明一个切点,用来切方法 -->
        <aop:pointcut id="myPoint" expression="execution(* com.aaa.Dao.*.*(..))"/>
         <!--声明一个切面 用来增强方法 -->
         <aop:aspect id="aspect" ref="myAspect" >
             <!-- method="myBefore"   指定通知的方法
                pointcut-ref="myPoint"     通知绑定的切点
                -->
             <aop:before method="myBefore" pointcut-ref="myPoint"></aop:before>
             <aop:before method="myBefore1" pointcut-ref="myPoint"></aop:before>
             <aop:after method="myAfter" pointcut-ref="myPoint"  ></aop:after>
             <aop:after-returning method="myAfterReturning" returning="result1" pointcut-ref="myPoint"></aop:after-returning>
             <aop:around method="myAround" pointcut-ref="myPoint"></aop:around>
            <aop:after-throwing method="myThrow" pointcut-ref="myPoint" throwing="throwable"></aop:after-throwing>
         </aop:aspect>

    </aop:config>

写切面:

package com.aaa.aop.AspectJ.xml;


import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;

/*
* 切面:公共代码抽取放置的位置
* */
public class MyAspect  {
    // 前置通知
    /*
    * joinPoint  是连接点,用来链接切点和切面的参数

    * */
    public void myBefore(JoinPoint joinPoint){
        System.out.println("前置方法生效");

    }
    public void myBefore1(JoinPoint joinPoint){
        System.out.println("前置方法2");
    }
    public void myAfter(JoinPoint joinPoint){
        System.out.println("最终方法生效");

    }
    //后置通知,目标方法执行调用,可以获取返回值
    public void myAfterReturning(JoinPoint joinPoint,Object result1){
        System.out.println("后置方法生效");
        System.out.println("执行的结果"+result1);
    }
    // 环绕通知 proceeding 开始;执行
    public Object myAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
        System.out.println("环绕通知开始--方法"+proceedingJoinPoint.getSignature().getName());
        Object result= proceedingJoinPoint.proceed();
        System.out.println("环绕通知的结果"+result);

        System.out.println("环绕通知结束方法:"+proceedingJoinPoint.getSignature().getName());
        return  result;
    }

    // 异常通知
    public void myThrow(JoinPoint joinPoint,Throwable throwable){
        System.out.println("异常通知");

    }








}

基于AspectJ注解的方式进行配置AOP

xml中:

    <!--开启全自动注解 -->
<context:component-scan base-package="com.aaa"></context:component-scan>

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

切面类中:

package com.aaa.aop.AspectJ.Annotation;

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

@Component // 将切面加到容器中去
@Aspect  // 声明当前类是一个切面
public class MyAspect {
    /*
    * 声明一个切点
    * */
    // public  void  com.aaa.Dao.StudentImpl.findStudent() throw
   //  省略     *    com.aaa.Dao.*.*(..)                   省略

    @Pointcut("execution( *    com.aaa.Dao.*.*(..) )")
   public void myPoint(){

   }
   @Before("myPoint()")
   public void myBefore(JoinPoint joinPoint){
       System.out.println("前置通知");
   }
   @After("myPoint()")
   public void myAfter(JoinPoint joinPoint){
       System.out.println("注解最终通知执行");
   }
   @AfterReturning(value = "myPoint()",returning = "result")
   public void myAfterRunning(JoinPoint joinPoint,Object result){
       System.out.println("后置方法执行"+result);
   }
   @Around("myPoint()")
    public Object myAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
       System.out.println("环绕方法执行");
         Object o= proceedingJoinPoint.proceed();
       System.out.println("执行结果为"+o);

       System.out.println("环绕通知结束");
       return o;
   }

   @AfterThrowing(value = "myPoint()",throwing = "throwable")
   public void myThrow(JoinPoint joinPoint,Throwable throwable){
       System.out.println("异常通知生效");
   }


}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值