spring03-----在spring中使用AOP

在Spring中默认使用JDK动态代理实现AOP编程,使用org.springframework.aop.framework.ProxyFactoryBean创建代理是Spring AOP 实现的最基本方式。



一、通知类型

根据Spring中通知在目标类方法中的连接点位置,通知可以分为6种类型:

类型名称作用应用场景
环绕通知(org.aopalliance.intercept.MethodInterceptor)在目标方法执行前和执行后实施增强可应用于日志记录、事务处理等功能。
前置通知(org.springframework.aop.MethodBeforeAdvice)在目标方法执行前实施增强可应用于权限管理等功能。
后置返回通知(org.springframework.aop.AfterReturningAdvice)在目标方法成功执行后实施增强可应用于关闭流、删除临时文件等功能。
后置通知(org.springframework.aop.AfterAdvice)在目标方法执行后实施增强,与后置返回通知不同的是,不管是否发生异常都要执行该类通知可应用于释放资源。
异常通知(org.springframework.aop.ThrowsAdvice)在方法抛出异常后实施增强可应用于处理异常、记录日志等功能。
引入通知(org.springframework.aop.IntroductionInterceptor)在目标类中添加一些新的方法和属性可应用于修改目标类(增强类)。Spring AOP 只支持方法层面的增强,所以该类型的通知只作为了解即可。



二、切面类型

切面类型作用
一般切面(Advisor)对目标类所有方法进行拦截
具有切点的切面(PointcutAdvisor)可以指定拦截目标类哪些方法
引介切面(IntroductionAdvisor)针对引介通知而使用切面



三、ProxyFactoryBean代理工厂

ProxyFactoryBean 是 org.springframework.beans.factory.FactoryBean 接口的实现类,这个类已经由spring为我们提供了,所以我们只需要在配置文件中进行配置就行了。FactoryBean 负责实例化一个Bean实例,ProxyFactoryBean 负责为其他 Bean 实例创建代理实例。ProxyFactoryBean 类的常用属性如下:

属性解释
target代理的目标对象
proxyInterfaces代理需要实现的接口列表,如果是多个接口,可以使用以下格式赋值:<list> <value></value> </list>
InterceptorNames需要织入目标的Advice
proxyTargetClass是否对类代理而不是接口,默认为false,使用JDK动态代理;当为true时,使用CGLIB动态代理
singleton返回的代理实例是否为单例,默认为true
optimize当设置为true时强制使用CGLIB动态代理



四、Advisor一般切面的实现

  1. 在pom.xml中导入AOP联盟和Spring-aop的相关依赖

    <!-- AOP联盟依赖 -->
    <dependency>
    	<groupId>aopalliance</groupId>
    	<artifactId>aopalliance</artifactId>
    	<version>1.0</version>
    </dependency>
    <dependency>
    	<groupId>org.springframework</groupId>
    	<artifactId>spring-aop</artifactId>
    	<version>5.0.2.RELEASE</version>
    </dependency>
    
  2. 创建StuDao接口和StuDaoImpl实现类
    StuDao接口:

    public interface StuDao {
    	public void save();
    	public void modify();
    	public void delete();
    }
    

    StuDaoLmpl实现类:

    public class StuDaoImpl implements StuDao {
    	@Override
    	public void save() {
        	System.out.println("保存");
    	}
    
    	@Override
    	public void modify() {
        	System.out.println("修改");
    	}
    
    	@Override
    	public void delete() {
        	System.out.println("删除");
    	}
    }
    
  3. 创建切面类MyBeforeAdvice

    import org.springframework.aop.MethodBeforeAdvice;
    import java.lang.reflect.Method;
    
    public class MyBeforeAdvice implements MethodBeforeAdvice {
    	@Override
    	public void before(Method method, Object[] objects, Object o) throws Throwable {
        	System.out.println("前置增强========");
    	}
    }
    
  4. 在applicationContext.xml中配置切面并指定代理

    <!--配置目标类-->
    <bean id="stuDao" class="aop.StuDaoImpl"></bean>
    
    <!--配置前置通知类型-->
    <bean id="myBeforeAdvice" class="aop.MyBeforeAdvice"></bean>
    
    <!--Spring AOP 生成代理对象-->
    <bean id="stuDaoProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
    
    	<!--配置目标类-->
    	<property name="target" ref="stuDao"></property>
    	
    	<!--代理实现的接口-->
    	<property name="proxyInterfaces" value="aop.StuDao"></property>
    	
    	<!--采取拦截的名称-->
    	<property name="interceptorNames" value="myBeforeAdvice"></property>
    </bean>
    
  5. 创建测试类

    @Test
    public void demo(){
    	ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
    	StuDao stuDao = (StuDao) app.getBean("stuDaoProxy");
    	stuDao.save();
    	stuDao.modify();
    	stuDao.delete();
    }
    



五、PointcutAdvisor切点切面的实现

使用普通Advice作为切面,将对目标类所有方法进行拦截,不够灵活,在实际开发中常采用带切点的切面。
常用PointcutAdvisor实现类:

DefaultPointcutAdvisor最常用的切面类型,它可以通过任意Pointcut和Advice组合定义切面;
JdkRegexpMethodPointcut构造正则表达式切点(推荐)

  1. 创建StuDao接口和StuDaoImpl实现类
    StuDao接口:
    public interface StuDao {
    	public void save();
    	public void modify();
    	public void delete();
    }
    
    StuDaolmpl实现类:
    public class StuDaoImpl implements StuDao {
    	@Override
    	public void save() {
        	System.out.println("保存");
    	}
    
    	@Override
    	public void modify() {
        	System.out.println("修改");
    	}
    
    	@Override
    	public void delete() {
        	System.out.println("删除");
    	}
    }
    
  2. 创建一个实现环绕通知的切面类
    import org.aopalliance.intercept.MethodInterceptor;
    import org.aopalliance.intercept.MethodInvocation;
    
    public class MyAspect implements MethodInterceptor {
    	@Override
    	public Object invoke(MethodInvocation m) throws Throwable {
        	//前置增强方法
        	check();
        	//执行目标方法
        	Object obj = m.proceed();
        	//后置增强方法
        	log();
        	return obj;
    	}
    
    	public void check(){
        	System.out.println("模拟权限控制");
    	}
    	public void log(){
        	System.out.println("模拟日志记录");
    	}
    }
    
  3. 在applicationContext.xml中配置切面并指定代理
    <!--配置目标类-->
    <bean id="stuDao" class="aop.StuDaoImpl"></bean>
    <!--配置通知-->
    <bean id="myAspect" class="aop.MyAspect"></bean>
    <!--配置带切入点的切面-->
    <bean id="myAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
     	<!--pattern中配置正则表达式:.表示任意字符 *表示任意次数-->
     	<property name="pattern" value=".*"></property>
     	<property name="advice" ref="myAspect"></property>
    </bean>
    <!--Spring AOP 生成代理对象-->
    <bean id="stuDaoProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
    	 <!--配置目标类-->
    	 <property name="target" ref="stuDao"></property>
    	 <!--代理实现的接口-->
    	 <property name="proxyInterfaces" value="aop.StuDao"></property>
    	 <!--采取拦截的名称-->
    	 <property name="interceptorNames" value="myAdvisor"></property>
    </bean>
    
  4. 创建测试类
    @Test
    public void demo(){
    	ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
    	StuDao stuDao = (StuDao) app.getBean("stuDaoProxy");
    	stuDao.save();
    	stuDao.modify();
    	stuDao.delete();
    }
    

原文地址:spring框架学习07——基于传统代理类的AOP实现  潘亚的博客

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值