码迷,mamicode.com
首页 > 编程语言 > 详细

Spring AOP学习

时间:2018-08-16 00:48:52      阅读:155      评论:0      收藏:0      [点我收藏+]

标签:ati   基础   work   ica   public   动态代理   异常   color   turn   

什么是AOP

 AOP 面向切面编程

采取横向抽取机制,取代了传统纵向继承体系重复性代码(性能监视、事务管理、安全检查、缓存)

 Spring AOP使用纯Java实现,不需要专门的编译过程和类加载器,在运行期通过代理方式向目标类织入增强代码

 AspecJ是一个基于Java语言的AOP框架,Spring2.0开始,Spring AOP引入对Aspect的支持,AspectJ扩展了Java语言,提供了一个专门的编译器,在编译时提供横向代码的织入

AOP底层原理

就是代理机制:

* 动态代理:(JDK中使用)

* JDK的动态代理,对实现了接口的类生成代理.

Spring的AOP代理

JDK动态代理:对实现了接口的类生成代理。没有实现接口的类,就无法生成代理对象了。

CGLib代理机制:对类生成代理

结论:Spring框架,如果类实现了接口,就使用JDK的动态代理生成代理对象,如果这个类没有实现任何接口,使用CGLIB生成代理对象.

AOP的术语

Joinpoint(连接点):所谓连接点是指那些被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点.

Pointcut(切入点):所谓切入点是指我们要对哪些Joinpoint进行拦截的定义.

Advice(通知/增强):所谓通知是指拦截到Joinpoint之后所要做的事情就是通知.通知分为前置通知,后置通知,异常通知,最终通知,环绕通知(切面要完成的功能)

Introduction(引介):引介是一种特殊的通知在不修改类代码的前提下, Introduction可以在运行期为类动态地添加一些属性方法.

Target(目标对象):代理的目标对象

Weaving(织入):是指把增强应用到目标对象来创建新的代理对象的过程.

spring采用动态代理织入,而AspectJ采用编译期织入和类装在期织入

Proxy(代理):一个类被AOP织入增强后,就产生一个结果代理类

Aspect(切面):是切入点和通知(引介)的结合

技术分享图片

 

不带有切点的切面

Spring按照通知Advice在目标方法的连接点位置,通知Advice可分为五类

前置通知:org.springframework.aop.MethodBeforeAdvice,在目标方法执行之前实施增强

后置通知:org.springframework.aop.AfterReturningAdvice,在目标方法执行之后实施增强

环绕通知:org.aopalliance.intercept.MethodInterceptor,在目标方法执行前后实施增强

异常抛出通知:org.springframework.aop.ThrowsAdvice,在方法抛出异常之后实施增强

引介通知:org.springframework.aop.IntroductionInterceptor,在目标类中添加一些新的方法和属性

Spring中切面的类型:

Advisor:Spring中的传统切面。

Aspect:都是有一个切点和一个通知的组合

Advisor:多个切点和多个通知的组合

 

Advisor : 代表一般切面,Advice本身就是一个切面,对目标类所有方法进行拦截(*不带有切点的切面)

PointcutAdvisor : 代表具有切点的切面,可以指定拦截目标类哪些方法带有切点的切面,针对某个方法进行拦截

 IntroductionAdvisor : 代表引介切面,针对引介通知而使用切面(不要求掌握)

不带切点的切面实例

导入相应的jar包:Spring开发基础包、spring-aop-4.3.7.RELEASE.jar、aopalliance-1.0.jar(AOP联盟包)

编写一个接口Customer:

package com.js.aopStu;
 
public interface CustomerDao {
    public void add();
    public void delete();
    public void update();
    public void find();
}

编写实现类CustomerImpl:

package com.js.aopStu;
 
public class CustomerImpl implements CustomerDao {
 
    @Override
    public void add() {    
        System.out.println("添加客户...");
    }
 
    @Override
    public void delete() {    
        System.out.println("删除客户...");
    }
 
    @Override
    public void update() {    
        System.out.println("修改客户...");
    }
 
    @Override
    public void find() {
        System.out.println("查询客户...");
    }
 
}

编写增强的代码。新建一个类MyBeforeAdvice,以前置增强为例

package com.js.aopStu;
 
import java.lang.reflect.Method;
 
import org.springframework.aop.MethodBeforeAdvice;
 
/**
 * 前置增强
 * 实现指定接口
 * @author hdb
 *
 */
public class MyBeforeAdvice implements MethodBeforeAdvice{
    /**
     * method:执行的方法
     * args:参数
     * target:目标对象
     */
    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println("前置增强...");
    }
    
}

配置代理生成代理类,基于ProxyFactoryBean类,底层自动选择使用JDK的动态代理还是CGLIB的代理。

配置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:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">

<!-- 定义目标对象 -->
<bean id="customerDao" class="com.js.aopStu.CustomerImpl"></bean>
<!-- 定义增强 -->
<bean id="beforeAdice" class="com.js.aopStu.MyBeforeAdvice"></bean>
 <!-- Spring支持配置来生成代理,基于ProxyFactoryBean类,底层自动选择使用JDK的动态代理还是CGLIB的代理 -->
 <bean id="customerDaoProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
 <!-- 设置目标对象 -->
     <property name="target" ref="customerDao"></property>
     <!-- 设置实现的接口,value中写接口的全路径 -->
     <property name="proxyInterfaces" value="com.js.aopStu.CustomerDao"></property>
     <!-- 配置需要拦截的,一定是value,此处对customerDao中的所有方法拦截 -->
     <property name="interceptorNames" value="beforeAdice"></property>
 </bean>

</beans>

 

我们需要配置一些属性,不需要都设置。

lProxyFactoryBean常用可配置属性
•target : 代理的目标对象
•proxyInterfaces : 代理要实现的接口
•如果多个接口可以使用以下格式赋值

<list>

    <value></value>

    ....

</list>

•proxyTargetClass : 是否对类代理而不是接口,设置为true时,使用CGLib代理
•interceptorNames : 需要织入目标的Advice
•singleton : 返回代理是否为单实例,默认为单例
•optimize : 当设置为true时,强制使用CGLib
(proxyInterfaces、proxyTargetClass二者互斥,不能同时存在)

编写测试类:

package com.js.aopStu;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
 
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class TestAOPDemo1 {
    
    @Autowired
    @Qualifier("customerDaoProxy")
    private CustomerDao customerDao;
    
    //不使用增强的情况下
    @Test
    public void Demo1(){
        customerDao.add();
        customerDao.delete();
        customerDao.find();
        customerDao.update();
    }
}

带有切点的切面(常用)

用PointcutAdvisor实现类,它有两个接口:
1、DefaultPointcutAdvisor:最常用的切面类型,它可以通过任意Pointcut和Advice 组合定义切面
2、RegexpMethodPointcutAdvisor:构造正则表达式切点切面一般使用这种

带有切点的切面实例

新建一个DAO,创建被代理对象:

package com.js.demo3;
/**
 * 目标对象
 * @author  hdb
 *
 */
public class OrderDao {
    public void add() {    
        System.out.println("添加订单...");
    }
    public void delete() {    
        System.out.println("删除订单...");
    }
    public void update() {    
        System.out.println("修改订单...");
    }
    public void find() {
        System.out.println("查询订单...");
    }
}

编写增强类,这次使用环绕增强:

package com.js.demo3;
 
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
 
/**
 * 增强的类
 * 使用的是环绕增强
 * @author hbd
 *
 */
public class MyAroundAdvice implements MethodInterceptor{
 
    @Override
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
        System.out.println("环绕前增强===");
        Object object=methodInvocation.proceed();//执行目标对象的方法
        System.out.println("环绕后增强===");
        return object;
    }
    
}

生成代理:通过配置的方式:

<?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:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">

<!-- 带有切点的切面 -->
<!-- 定义目标对象 -->
<bean id="orderDao1" class="com.js.demo3.OrderDao"></bean>

<!-- 定义增强 -->
<bean id="aroundAdvice" class="com.js.demo3.MyAroundAdvice"></bean>

<!-- 定义切点切面: -->
<bean id="myPointcutAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
    <!-- 定义表达式,规定哪些方法执行拦截 -->
    <!-- . 任意字符  * 任意个 -->
    <!-- <property name="pattern" value=".*"/> -->
    <!-- <property name="pattern" value="cn\.itcast\.spring3\.demo4\.OrderDao\.add.*"/> -->
    <!-- <property name="pattern" value=".*add.*"></property> -->
    <property name="patterns" value=".*add.*,.*find.*"></property>
    <!-- 应用增强 -->
    <property name="advice" ref="aroundAdvice"/>
</bean>

<!-- 定义生成代理对象 -->
<bean id="orderDaoProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
    <!-- 配置目标 -->
    <property name="target" ref="orderDao1"></property>
    <!-- 针对类的代理 -->
    <property name="proxyTargetClass" value="true"></property>
    <!-- 在目标上应用增强 -->
    <property name="interceptorNames" value="myPointcutAdvisor"></property>
</bean>

</beans>

编写测试类:

package com.js.demo3;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
 
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class TestAOPDemo1 {
@Autowired @Qualifier(
"orderDaoProxy") private OrderDao orderDao;
@Test
public void demo1(){ orderDao.add(); orderDao.delete(); orderDao.find(); orderDao.update(); } }

 

Spring AOP学习

标签:ati   基础   work   ica   public   动态代理   异常   color   turn   

原文地址:https://www.cnblogs.com/huangdabing/p/9484349.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!