Spring IOC AOP (二)

本文通过实例介绍Spring AOP(面向切面编程)的实现方式,包括使用注解和XML配置的方法,详细解释了@Before、@AfterReturning、@AfterThrowing等通知的应用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

spring AOP(Aspect Oriented Programming面向切面编程)和ioc是spring两大核心。面试时也会有很多面试官提问这些问题。通过一些例子加深对aop的印象。
在理解aop的基础上,首先应该明白什么是动态代理和反射。因为Spring框架里面大量的使用了动态代理和反射机制。这是我根据别人的相关代码总结的反射和动态代理
()Spring 实现动态代理配置有两种配置文件:1.xml文件方式,
2.annotation方式(使用Aspectj类库实现。)
spring 的相关概念:joinpoint:

Spring支持五种类型的通知:
Before(前) org.apringframework.aop.MethodBeforeAdvice
After-returning(返回后) org.springframework.aop.AfterReturningAdvice
After-throwing(抛出后) org.springframework.aop.ThrowsAdvice
Arround(周围) org.aopaliance.intercept.MethodInterceptor
Introduction(引入) org.springframework.aop.IntroductionInterceptor

在下面的小例子中说明spring通过注解是如何实现代理的。
首先在配置文件添加关于aspectj这是专门用来实现代理的框架。
beans.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-2.5.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-2.5.xsd
           http://www.springframework.org/schema/aop
           http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">       
    <context:annotation-config />
    <context:component-scan base-package="com.neusoft"/>
    <aop:aspectj-autoproxy />
    <!-- 
    <bean id="userImpl" class="com.neusoft.impl.UserImpl"></bean>
    <bean id="userService" class="com.neusoft.service.UserService">
    <property name="user">
    <ref bean="userImpl"/>
    </property>
    </bean>
     -->
</beans>
package com.neusoft.dao;

public interface User {
  public String add();
}
package com.neusoft.impl;

import org.springframework.stereotype.Component;

import com.neusoft.dao.User;
@Component("userImpl")
public class UserImpl implements User{

    @Override
    public void add() {
        System.out.println("*****这里是add方法*******");


    throw  new RuntimeException("Exception!");
    }
}



package com.neusoft.service;

import javax.annotation.Resource;

import org.springframework.stereotype.Component;

import com.neusoft.dao.User;
@Component("userService")
public class UserService {

    private User user;

    public void addUser(){

        user.add();
    }


    @Resource(name="userImpl")
 public void setUser(User user) {
        this.user = user;
    }



}

package com.neusoft.aop;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;

@Aspect
@Controller /*这里spring2.5里Component、service、Repository等注解用处差不多。用来初始化AopExample 
这个类,这样spring才能把AopExample 和add()关联起来。
*/
public class AopExample {
     /* 我们要把doBefore()这个方法在add()方法之前执行;
     ("execution(public void add())")。  
    在service包或其子包中定义的任意方法的执行:
    execution(* com.xyz.service..*.*(..))


     */
    @Before(value="execution(public void com.neusoft.impl.UserImpl.add())")
      //@Before(value="execution(public * com.neusoft.impl..*.*(..))")和上面表达意思一致

     /*
    执行结果:
    @Before**在add方法前执行***
    *****这里是add方法*******

    */
  public void doBefore(){

      System.out.println("**在add方法前执行***");
  }

    @AfterReturning(value="execution(public * com.neusoft.impl..*.*(..))")

      /*
     执行结果:
     *****这里是add方法*******
     @AfterReturning**在add方法后执行***
    */
      public void doAfter(){

          System.out.println("@AfterReturning**在add方法后执行***");
      }

        @AfterThrowing("execution(public * com.neusoft.impl..*.*(..))")
    //让UserImpl中抛个异常信息;在UserImpl自己定义一个异常。

      /* 
      执行结果:
      *****这里是add方法*******
      @AfterThrowing**在add方法后执行***
       */
      public void afterThrowing(){

          System.out.println("@AfterThrowing**在add方法后执行***");
      }
          //环绕通知:在方法执行前后和抛出异常时执行,相当于综合了以上三种通知
    @Around("execution(public * com.neusoft.impl..*.*(..))")
    /*
       执行结果:
       @Around**在add方法前执行***
       *****这里是add方法*******
       @AfterThrowing**在add方法后执行***
     * 
     */

      public void around(ProceedingJoinPoint pjp) throws Throwable{
           System.out.println("@Around**在add方法前执行***");
           pjp.proceed();
           System.out.println("@AfterThrowing**在add方法后执行***");
      }

}

如果你觉得上面@Before、@AfterReturning、@AfterThrowing这些通知后面每次都要加(“execution(public * com.neusoft.impl...(..))”)
太麻烦的话,也可以自己定义一个方法。使用形式如下:

@Pointcut(“execution(public * com.neusoft.service...(..))”) public
void Method(){}
@Before(“Method()”)
public void doBefore(){
System.out.println(“在add方法前执行*“);
}

XML配置形式。


    <bean id="userImpl" class="com.neusoft.impl.UserImpl"></bean>
    <bean id="userService" class="com.neusoft.service.UserService">
    <property name="user">
    <ref bean="userImpl"/>
    </property>
    </bean>
  <bean id="aopExample" class="com.neusoft.aop.AopExample"></bean>
  <aop:config >
   <aop:aspect id="aspect" ref="aopExample">
   <aop:pointcut expression="execution(public * com.neusoft.impl..*.*(..))" id="impl"/>
  <aop:before method="doBefore" pointcut-ref="impl"/>
  <aop:after-returning method="doAfter" pointcut-ref="impl"/>
  <aop:after-throwing method="afterThrowing" throwing="ex" pointcut-ref="impl"/>
  <aop:around method="around" pointcut-ref="impl"/>
   </aop:aspect> 
  </aop:config> 

到这里大致就把注解中spring aop的知识点总结了一遍,这时候如果我们的AopIpml在service层增加逻辑会不会结果也和在impl层一样呢?
实验得知控制台会报错,原因就是我们service层UserService 没有实现接口,实现借口后,就会使用jdk自带的 Proxy,InvocationHandler来帮助
你产生代理。如果没有实现接口,就会直接操作二进制码的类库(cglib)来实现代理。加入cglib架报即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值