5.Spring与AOP-通知(Advice)

通知(Advice),切面的一种实现,可以完成简单织入功能(织入功能就是在这里完成的)。常用通知有:前置通知、后置通知、环绕通知、异常处理通知

一、前置通知(MethodBeforeAdvice)

定义前置通知需要实现MethodBeforeAdvice接口。该接口中有一个方法before(),会在目标方法执行之前执行。前置通知的特点:

  • 在目标方法执行之前先执行
  • 不改变目标方法的执行流程,前置通知代码不能阻止目标方法执行
  • 不改变目标方法执行的结果

接口类

//主业务接口
public interface ISomeService {
    String doFirst();
    void doSecond();
}

实现类

//目标类:代理类要增强的类
public class SomeServiceImpl implements ISomeService {
    @Override
    
    public String doFirst() {
        //SystemService.doTx();
        System.out.println("执行doFirst()方法");
        //SystemService.doLog();
        return "abcde";
    }

    @Override
    public void doSecond() {
        //SystemService.doTx();
        System.out.println("执行doSecond()方法");
        //SystemService.doLog();
    }
}

前置通知类

public class MyMethodBeforeAdvice implements MethodBeforeAdvice {
	//当前方法在目标方法执行之前执行
	/*
		method:目标方法
		args:目标方法的参数列表
		target:目标对象
	*/
    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {
    	//对于目标方法的增强代码就应该写在这里
        System.out.println("执行前置通知方法!!!");
    }
}

xml配置

	 <!--注册切面:前置通知-->
    <bean id="myAdvice" class="com.chen.service.MyMethodBeforeAdvice"/>
     <!--生成代理对象-->
    <bean id="serviceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
        <!--<property name="targetName" value="someService"/>-->
        <!--指定目标对象-->
        <property name="target" ref="someService"/>
        <!--指定切面-->
        <property name="interceptorNames" value="myAdvice"/>
    </bean>

测试及结果

	@Test
    public void test01() {
        //创建容器对象,加载Spring配置文件
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
        ISomeService service = (ISomeService) ac.getBean("serviceProxy");
        service.doFirst();
        System.out.println("= = =");
        service.doSecond();
    }
    /*
    	执行前置通知方法!!!
		执行doFirst()方法
		= = =
		执行前置通知方法!!!
		执行doSecond()方法	
    */

二、后置通知(AfterReturuningAdvice)

后置通知类

public class MyAfterRreturningAdvice implements AfterReturningAdvice {

    //在目标方法执行之后执行
    //returnValue:目标方法的返回值
    @Override
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
        System.out.println("执行后置通知方法 returnValue = " + returnValue);
    }
}

xml配置

	 <!--注册切面:后置通知-->
    <bean id="myAfterRreturningAdvice" class="com.chen.service.MyAfterRreturningAdvice"/>
     <!--生成代理对象-->
    <bean id="serviceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
        <!--<property name="targetName" value="someService"/>-->
        <!--指定目标对象-->
        <property name="target" ref="someService"/>
        <!--指定切面-->
        <!--<property name="interceptorNames" value="myAdvice"/>-->
        <property name="interceptorNames" value="myAfterRreturningAdvice"/>

    </bean>

测试及结果

	//后置通知测试
    @Test
    public void test02() {
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
        ISomeService service = (ISomeService) ac.getBean("serviceProxy");
        service.doFirst();
        System.out.println("= = = =");
        String result = service.doSecond();
        System.out.println(result);
        /*
			执行doFirst()方法
			执行后置通知方法 returnValue = abcde
			= = = =
			执行doSecond()方法
			执行后置通知方法 returnValue = abcde
			abcde	
		*/
    }

三、环绕通知(MethodInterceptor)

环绕通知类

//环绕通知:可以修改目标方法的返回结果
public class MyMethodInterceptor implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
        System.out.println("执行环绕通知:目标方法执行之前");

        //执行目标方法
        Object result = methodInvocation.proceed();

        System.out.println("执行环绕通知:目标方法执行之前之后");
        if (result != null) {
            result = ((String)result).toUpperCase();
        }
        return result;
    }
}

xml配置

	<!--注册切面:环绕通知-->
    <bean id="myMethodInterceptor" class="com.chen.service.MyMethodInterceptor"/>
    <!--生成代理对象-->
    <bean id="serviceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
        <!--<property name="targetName" value="someService"/>-->
        <!--指定目标对象-->
        <property name="target" ref="someService"/>
        <!--指定切面-->
        <!--<property name="interceptorNames" value="myAdvice"/>-->
        <property name="interceptorNames" value="myMethodInterceptor"/>

    </bean>

测试及结果

	 @Test
    public void test03() {
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
        ISomeService service = (ISomeService) ac.getBean("serviceProxy");
        service.doFirst();
        System.out.println("= = = = =");
        String result = service.doSecond();
        System.out.println(result);
    }
    /*
		执行环绕通知:目标方法执行之前
		执行doFirst()方法
		执行环绕通知:目标方法执行之前之后
		= = = = =
		执行环绕通知:目标方法执行之前
		执行doSecond()方法
		执行环绕通知:目标方法执行之前之后
		ABCDE	
	*/

四、异常通知(ThrowsAdvice)

异常类

  1. UserException.java
/*
* 异常分为两种:
* 1、运行时异常,不进行处理也可以通过编译;
*       若一个类继承自RunTimeException,则该异常就是运行时异常
* 2、编译时异常、受查异常,Checked Exception,不进行处理,将无法通过编译;
*       若一个类继承自Exception,则该异常就是受查异常
* */
public class UserException extends Exception {
    public UserException(){
        super();
    }

    public UserException(String message) {
        super(message);
    }
}
  1. UsernameException.java
public class UsernameException extends UserException {
    public UsernameException() {
        super();
    }

    public UsernameException(String message) {
        super(message);
    }
}
  1. PasswordException.java
public class PasswordException extends UserException {
    public PasswordException() {
        super();
    }

    public PasswordException(String message){
        super(message);
    }
}

接口

public interface IUserService {
    //目标方法
    boolean login(String username, String password) throws UserException;
}

实现类

public class UserServiceImpl implements IUserService {
    @Override
    public boolean login(String username, String password) throws UserException {
        if (!"beijing".equals(username)){
            throw new UsernameException("用户名输错了");
        }
        if (!"111".equals(password)) {
            throw new PasswordException("密码输错了");
        }
        // double a = 3/0;
        return true;
    }
}

异常通知类

//异常通知
public class MyThrowsAdvice implements ThrowsAdvice {

    //当目标方法抛出UsernameException异常时,执行当前方法
    public void afterThrowing(UsernameException ex) {
        System.out.println("发生用户名异常 ex = " + ex.getMessage());
    }

    //当目标方法抛出PasswordException异常时,执行当前方法
    public void afterThrowing(PasswordException ex) {
        System.out.println("发生密码异常 ex = " + ex.getMessage());
    }

    //当目标方法抛出Exception异常时,执行当前方法
    public void afterThrowing(Exception ex) {
        System.out.println("发生异常 ex = " + ex.getMessage());
    }

}

xml配置

	<!--注册切面:异常通知-->
    <bean id="myThrowsAdvice" class="com.chen.service.MyThrowsAdvice"/>
    
    <!--注册目标对象-->
    <bean id="userService" class="com.chen.service.UserServiceImpl"/>
    
    <!--生成代理对象-->
    <bean id="serviceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
        <!--<property name="targetName" value="someService"/>-->
        <!--指定目标对象-->
        <property name="target" ref="userService"/>
        <!--指定切面-->
        <!--<property name="interceptorNames" value="myAdvice"/>-->
        <property name="interceptorNames" value="myThrowsAdvice"/>

    </bean>

测试

	@Test
    public void test05() throws Exception{
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
        IUserService service = (IUserService) ac.getBean("serviceProxy");
        service.login("beijing", "111");

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值