Spring配置过程 (二)面向切面编程AOP

一  配置过程

1.创建项目

2.导包
    Spring的包
    增加:
    aopalliance
    aspectjweaver

3.创建Dao层接口及实现层

4.创建通知类及要执行的通知方法

5.配置ApplicationContext.xml

        配置bean
        配置AOP   aop:config
        配置切点   aop:pointcut
                         id
                         expression  "execution(针对的方法)"

        配置切面  aop:aspect
                         id
                         ref
        配置连接点
                         aop:before
                         aop:after
                         aop:after-returning    
                         aop:around    
                         aop:after-throwing

6.写测试类

二  示例

配置文件实现

1.创建项目SpringAop1

2.导入需要的包

3.创建Dao层接口IUserDao

package com.hp.dao;

public interface IUserDao {
	int login(String name,String password);
	int div(int a,int b);
}

创建Dao层实现UserDaoImpl

package com.hp.dao.impl;

import com.hp.dao.IUserDao;

public class UserDaoImpl implements IUserDao {

	@Override
	public int login(String name, String password) {
		if("admin".equals(name) && "123".equals(password)){
			System.out.println("登录成功");
			return 1;
		}
		else{
			System.out.println("登录失败");
		}
		return 0;
	}

	@Override
	public int div(int a, int b) {
		
		int res=a/b;  //b=0时抛出异常
		return res;
		
	}

}

4.创建通知类及要执行的通知方法LogAdvice

package com.hp.advice;

import org.aspectj.lang.JoinPoint;

public class LogAdvice {
	
	public void before(JoinPoint jp){
		/*
		 * 如何才能知道调用的是哪一个方法
		 * 给before方法添加一个参数JoinPoint
		 */
		
		String methodName = jp.getSignature().getName();     //获取方法名
		Object[] args = jp.getArgs();     //获取参数
		System.out.println("前置通知");
		System.out.println("将要执行:"+methodName+"方法");
		System.out.println("参数列表:");
		for (Object object : args) {
			System.out.println(object);
		}
	}
	
	public void after(JoinPoint jp){
		String methodName = jp.getSignature().getName();  
		System.out.println(methodName + "方法执行结束");
		System.out.println("后置通知");
	}
	
	public void afterReturning(Object res) throws Throwable{
		System.out.println("返回值:"+res);
		System.out.println("返回通知");
	}
	
	public void afterThrowing(Exception ex){
		System.out.println("异常信息:"+ex.getMessage());
		System.out.println("分母不能为0");
	}
}

5.配置ApplicationContext.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:tx="http://www.springframework.org/schema/tx"
       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/tx  
                            http://www.springframework.org/schema/tx/spring-tx.xsd
                            http://www.springframework.org/schema/context 
                            http://www.springframework.org/schema/context/spring-context.xsd
                            http://www.springframework.org/schema/aop 
                            http://www.springframework.org/schema/aop/spring-aop-4.1.xsd">
                   
                  <!-- 声明bean -->       
                  <bean id="IUserDao"  class="com.hp.dao.impl.UserDaoImpl" ></bean>
                  <bean id="logAdvice" class="com.hp.advice.LogAdvice"></bean>
        			
        		  <!-- 配置AOP -->
        		  <aop:config>
        		  <!-- 配置切入点 -->
        		  <!-- 第一个*表示访问符和返回类型任意,括号里的两个点表示任意参数 -->
        		  	<aop:pointcut expression="execution(* com.hp.dao.*.*(..))"  id="logPoint" />
        		  	<!-- 配置切面 -->
        		  	<aop:aspect id="logAspect" ref="logAdvice" >
        		  		<!-- 配置连接点 -->
        		  		<aop:before method="before"  pointcut-ref="logPoint" /> 
        		  		<aop:after method="after" pointcut-ref="logPoint"/>
        		  		<aop:after-returning method="afterReturning" pointcut-ref="logPoint" returning="res"/>
        		  		<aop:after-throwing method="afterThrowing" pointcut-ref="logPoint"  throwing="ex"/>
        		  	</aop:aspect>
        		  </aop:config> 
</beans>

6.写测试类MainTest

package com.hp.test;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.hp.dao.IUserDao;

public class MainTest {
	@Test
	public void login() throws Exception{
	ApplicationContext context=new ClassPathXmlApplicationContext("ApplicationContext.xml");
	IUserDao iUserDao = (IUserDao) context.getBean("IUserDao");
	 iUserDao.login("admin", "123");
	 System.out.println("-------------");
	 iUserDao.div(1, 0);
	}
}
7.运行结果:

前置通知
将要执行:login方法
参数列表:
admin
123
登录成功
login方法执行结束
后置通知
返回值:1
返回通知
-------------
前置通知
将要执行:div方法
参数列表:
1
0
div方法执行结束
后置通知
异常信息:/ by zero
分母不能为0
8.项目结构:



注解实现

1.创建项目SpringAop2

2.导入需要的包(同上)

3.创建Dao层接口IUserDao

package com.hp.dao;

public interface IUserDao {
	int login(String name,String password);
	int div(int a,int b);
}

创建Dao层实现UserDaoImpl

package com.hp.dao.impl;

import org.springframework.stereotype.Repository;

import com.hp.dao.IUserDao;
@Repository("IUserDao")
public class UserDaoImpl implements IUserDao {

	@Override
	public int login(String name, String password) {
		if("admin".equals(name) && "123".equals(password)){
			System.out.println("登录成功");
			return 1;
		}
		else{
			System.out.println("登录失败");
		}
		return 0;
	}

	@Override
	public int div(int a, int b) {
		
		int res=a/b;  //b=0时抛出异常
		return res;
		
	}
}

4.创建通知类及要执行的通知方法LogAdvice

package com.hp.advice;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

@Aspect
@Component  //(把普通pojo实例化到spring容器中,相当于配置文件中的<bean id="" class=""/>)
public class LogAdvice {
	
	@Pointcut("execution(* com.hp.dao.*.*(..))")
	private void anyMethod(){}   //声明一个切入点,anyMethod为切入点名称
	
	@Before("anyMethod()")
	public void before(JoinPoint jp){
		/*
		 *  如何才能知道调用的是哪一个方法
		 *  给before方法添加一个参数JoinPoint
		 */
		
		String methodName = jp.getSignature().getName();//获取方法名
		Object[] args = jp.getArgs();//获取参数
		System.out.println("前置通知");
		System.out.println("将要执行:"+methodName+"方法");
		for (Object object : args) {
			System.out.println(object);
		}
	}

	@After("anyMethod()")
	public void after(JoinPoint jp){
		String methodName = jp.getSignature().getName();
		System.out.println(methodName+"方法执行结束");
		System.out.println("后置通知");
	}	
	
	@AfterReturning(pointcut ="anyMethod()", returning="res")
	public void afterReturning(Object res) throws Throwable{
		System.out.println("方法返回值:"+res);
		System.out.println("返回通知");
	}
	
	@AfterThrowing(pointcut = "anyMethod()", throwing="ex")
	public void afterThrowing(Exception ex){
		System.out.println("异常信息:"+ex.getMessage());
		System.out.println("分母不能为0");
	}
}

5.配置ApplicationContext.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:tx="http://www.springframework.org/schema/tx"
       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/tx  
                            http://www.springframework.org/schema/tx/spring-tx.xsd
                            http://www.springframework.org/schema/context 
                            http://www.springframework.org/schema/context/spring-context.xsd
                            http://www.springframework.org/schema/aop 
                            http://www.springframework.org/schema/aop/spring-aop-4.1.xsd">
               
           <!-- spring注解 -->  
        <context:component-scan base-package="com.hp.dao,com.hp.advice" />  
                            
       <aop:aspectj-autoproxy></aop:aspectj-autoproxy>    
                  
</beans>

6.写测试类MainTest

package com.hp.test;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.hp.dao.IUserDao;

public class MainTest {
	@Test
	public void login() throws Exception{
	ApplicationContext context=new ClassPathXmlApplicationContext("ApplicationContext.xml");
	IUserDao iUserDao = (IUserDao) context.getBean("IUserDao");
	 iUserDao.login("admin", "123");
	 System.out.println("-------------");
	 iUserDao.div(1, 0);
	}
}
7.运行结果:
前置通知
将要执行:login方法
参数列表:
admin
123
登录成功
login方法执行结束
后置通知
返回值:1
返回通知
-------------
前置通知
将要执行:div方法
参数列表:
1
0
div方法执行结束
后置通知
异常信息:/ by zero
分母不能为0
8.项目结构:



三   问题研究

1. 在返回通知中,如何获取返回值?
    xml中<aop:after-returning method="afterReturning" pointcut-ref="logPoint" returning="res"/>
    Advice中传递一个Object类型的res参数
2. 在异常通知中,如何获取出现的异常?
    xml:<aop:after-throwing method="afterThrowing" pointcut-ref="logPoint"  throwing="ex"/>
    Advice中传递一个Exception类型的ex参数
    Advice中ex.getMessage()
3. 当异常出现时,返回通知和后置通知还会执行吗?
     返回通知不会执行,后置通知会执行

4. 当后置通知与返回通知同时存在时,哪一个先执行呢?
     执行顺序按照在xml配置文件中的配置顺序执行

四  XML配置方式与注解方式对比

1. 使用注解时,需要在XML配置文件中添加<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
2. @ Component注解,相当于配置文件中的,<bean >
3. @ Pointcut注解,相当于配置文件中的,<aop:pointcut>
4. @ Aspect注解,相当于配置文件中的, <aop:aspect>
5. @ Before注解,相当于配置文件中的.<aop:before> after afterrunning afterthrowing around

注:异常通知,比较常用, 我们在编写Dao层和Service层时,可以完全不作异常处理,而且创建一个专门的异常通知切面,由这个异常处理通知类专门负责处理各种异常。

原文地址:https://www.cnblogs.com/mlan/p/11060356.html