五、spring之AOP

五、spring之AOP


一、aop概念

AOP(Aspect Oriented Programming),即面向切面编程,是面向对象编程的的有力补充。面向对象编程关注的主要是业务处理,与之关系不大的部分是切面关注点。他们经常发生在核心业务的多处,而各处基本相似,比如权限认证、日志、事物。AOP的作用在于分离系统中的各种关注点,将核心业务和切面关注点分离开来。主要是利用动态代理来实现AOP的。
1、连接点(joinpoint)
程序执行过程中明确的点,如方法的调用,在Spring中连接点指的就是被拦截到的方法;
2、切入点(pointcut)
对连接点的定义(也可以说是被增强的方法)
3、通知(Advice)
aop在特定切入点执行的增强处理,(前置通知,后置通知,异常通知,最终通知,环绕通知)等
4、切面(aspect)
切入点和通知(引介)的结合: 对哪个方法进行怎么样增强(增强的方法,执行通知类型)advice;
5、织入(weave)
将切面应用到目标对象并创建代理对象的过程
6、引介(Introduction)是一种特殊的通知在不修改类代码的前提下, Introduction可以在运行期为类动态地添加一些方法或Field。
7、Target(目标对象): 代理的目标对象。
8、Proxy(代理): 一个类被AOP织入增强后,就产生一个结果代理类。

二、基于xml的aop配置

1.将切面类交给spring容器管理
2. aop:config标签: 声明aop配置
3. aop:pointcut子标签 :在aop:config中,定义切入点
expression属性:定义切入点表达式,例如:”execution( cn.it...(..))”
id属性:定义该切入点在spring容器中的唯一表示*
4.aop:aspect子标签:定义通知类型(相当于一个切面)
1|.ref属性:切面类的引用
2|.子标签:
1)aop:before:前置通知
2)aop:after 最终通知
3)aop:after-returning 后置通知
4)aop:after-throwing 异常通知
5)aop:around 环绕通知
3|子标签的属性:
1)method:通知引用的方法(从切面类中引用)
2)pointcut-ref:切入点的引用
3)pointcut:切入点表达式
说明 aspect的ref属性(切面类引用)和其子标签method属性(该通知从切面类中引用的方法),可以完整定位一个通知,再通过pointcut切入点的引用,完成织入过程。

    <!-- 配置springAop(使用aop的名称空间)
             1.将切面类交给spring管理
    -->
    <bean id="TransactionManger" class="cn.it.transaction.TransactionManger"></bean>

    <!--aop配置信息-->
    <aop:config>
        <!-- 配置一个切入点表达式 :定位被增强方法的
            aop:pointcut :
                id:切入点的唯一标识
                expression: 切入点表达式
                    完整写法: execution(类的修饰符 返回值 包名.包名.类名.方法名(参数列表))
                    1.类的修饰符可以省略
                    2.返回值可以使用*号代替,标识任意返回值类型
                    3.包名可以使用*号代替,代表任意包,有一个包,需要写一个*号
                    4.可以使用..表示此包,以及此包下的所有子包
                    5.类名可以使用*号代替,表示所有类
                    6.方法名可以使用*号代替,表示任意方法
                    7.可以使用..代表任意参数
        -->

        <aop:pointcut expression="execution(* cn.it.service.impl.*.*(..))" id="cutPoint"/>


               <!-- 配置通知类型
                    aop:aspect (切面) 
                       1.ref属性:切面类的引用
                       2.子标签:
                            1)aop:before:前置通知
                            2)aop:after  最终通知
                            3)aop:after-returning  后置通知 
                            4)aop:after-throwing  异常通知
                            5)aop:around  环绕通知
                           3子标签属性:
                               1)method:通知引用的方法(从切面类中引用)
                               2)pointcut-ref:切入点的引用
                               3)pointcut:切入点表达式
                    --> 
        <aop:aspect ref="TransactionManger">
            <aop:before method="Before" pointcut-ref="**cutPoint**"/>
            <aop:after-returning method="AfterReturning"  pointcut-ref="cutPoint"/>
            <aop:after-throwing method="AfterThrowing"  pointcut="execution(* cn.it.service.impl.*.*(..))"/>
            <aop:after method="After" pointcut-ref="cutPoint"/>

        <!-- <aop:around method="around" pointcut-ref="cutPoint"/>-->

        </aop:aspect>   

    </aop:config>

三、基于xml和注解的aop实现

xml配置

    <!-- 1开启对ioc注解的支持:定义扫描的包 -->
    <context:component-scan base-package="cn.it" ></context:component-scan>
    <!-- 2开启对Aop注解的支持 -->
    <aop:aspectj-autoproxy ></aop:aspectj-autoproxy>

切面类注解

package cn.it.transaction;

import java.sql.Connection;
import java.sql.SQLException;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

import cn.it.utils.ConnectionUtils;

/**
 * 此类:是一个切面类
 *      * 定义的方法,全部都是增强的代码逻辑
 * 一个通知类型,对应一个切面方法
 * 
 * 1.声明切面类
 *      @Aspect
 * 2.定义切入点
 *      @Ponitcut
 *          value:切入点表达式
 *          方法名()
 * 3.定义通知类型
 *      @Before
 *      @AfterReturning
 *      @AfterThrowing
 *      @After
 *      @Around
 * * value :配置切入点的引用,或者切入点表达式
 * 
 */
@Component
@Aspect
public class TransactionManger {
    /**
     * @Pointcut:定义公共的切入点
     *    1.需要配置到一个空的方法上
     *    2.value:切入点表达式
     *    3.其他的地方引用此切入点的时候 : 方法名()
     */
    @Pointcut(value="execution(* cn.it.service.impl.*.*(..))")
    public void cutPoint() {};

    //@Before("cutPoint()")
    public void Before() throws SQLException {
        System.out.println("前置通知");
        Connection connection = ConnectionUtils.getInstance().getConnection();
        connection.setAutoCommit(false);
    }

    //@After("execution(* cn.it.service.impl.*.*(..))")
    public void After() throws SQLException {

        System.out.println("最终通知");
        Connection connection = ConnectionUtils.getInstance().getConnection();
        connection.setAutoCommit(true);
        connection.close();
    }

    //@AfterReturning("cutPoint()")
    public void AfterReturning() throws SQLException {
        System.out.println("后置通知");
        Connection connection = ConnectionUtils.getInstance().getConnection();
        connection.commit();

    }

    //@AfterThrowing("cutPoint()")
    public void AfterThrowing() throws SQLException {
        System.out.println("异常通知");
        Connection connection = ConnectionUtils.getInstance().getConnection();
        connection.rollback();
    }
    /**
     * 环绕通知:
     *     spring提供的一种通知类型,可以让程序员灵活的配置增强代码逻辑的执行过程
     *     具有拦截和放行的功能
     *        代码写法:和自定义动态代理方法中的增强逻辑类似
     *                            将前置通知,后置通知,异常通知,最终通知,全部都要定义在环绕通知中!
     *     1.ProceedingJoinPoint : 连接点对象
     *     2.proceed:内部可以调用被代理对象的方法
     *     3.返回值 : object   
     *               被代理对象方法的返回值
     */
    @Around("cutPoint()")
    public Object around(ProceedingJoinPoint pj) throws Throwable {
        Connection conn = ConnectionUtils.getInstance().getConnection();
        Object proceed = null;

        try {
            System.out.println("前");
            conn.setAutoCommit(false);
            proceed = pj.proceed();
            System.out.println("后");
            conn.commit();
        } catch (Exception e) {
            System.out.println("异常");
            conn.rollback();
        } finally {
            System.out.println("最终");
            conn.setAutoCommit(true);
            conn.close();
        }

        return proceed;
    }

}

四、基于注解的aop实现

  • 将切面类对象交给spring容器管理(ioc注解)
  • 开启对注解们的支持
    * 对ioc注解的支持
    * 开启对aop注解的支持
    1.声明切面类
    @Aspect
    @Component 交spring管理
    2.定义切入点
    @Ponitcut
    @Pointcut:定义公共的切入点
    • 1).需要配置到一个空的方法上
    • 2).value:切入点表达式
    • 3.)其他的地方引用此切入点的时候 : 方法名()
      3.定义通知类型
      @Before
      @AfterReturning
      @AfterThrowing
      @After
      @Around
      • value :配置切入点的引用,或者切入点表达式
        @EnableAspectJAutoProxy:开启对aop注解的支持
        @ComponentScan(basePackages=”cn.it”):开启对包扫描的支持
        核心配置类的声明
/**
 * 1.声明配置类
 * 2.定义扫描的包
 * 3.开启对Aop注解的支持
 * 4.导入其他配置文件
 *
 */
@Configuration
@ComponentScan(basePackages="cn.it")
@EnableAspectJAutoProxy
@Import(jdbcConfig.class)

public class SpringConfig {


}

切面类的注解

package cn.it.transaction;

import java.sql.Connection;
import java.sql.SQLException;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import cn.it.utils.ConnectionUtils;

/**
 * 此类:是一个切面类
 *      * 定义的方法,全部都是增强的代码逻辑
 * 一个通知类型,对应一个切面方法
 * 
 * 1.声明切面类,交给spring管理
 *      @Aspect 声明切面类
        @Component 将切面类交spring管理  
 * 2.定义切入点
 *      @Ponitcut
 *          value:切入点表达式
 *          方法名()
 * 3.定义通知类型
 *      @Before
 *      @AfterReturning
 *      @AfterThrowing
 *      @After
 *      @Around
 * * value :配置切入点的引用,或者切入点表达式
 * 
 */
@Component
@Aspect
public class TransactionManger {
    /**
     * @Pointcut:定义公共的切入点
     *    1.需要配置到一个空的方法上
     *    2.value:切入点表达式
     *    3.其他的地方引用此切入点的时候 : 方法名()
     */

    @Pointcut(value="execution(* cn.it.service.impl.*.*(..))")
    public void cutPoint() {
    };

       @Autowired
        private ConnectionUtils cUtils;

    //@Before("cutPoint()")
    public void  Before() throws SQLException {
        System.out.println("前置通知");
        Connection connection = cUtils.getConnection();
        connection.setAutoCommit(false);
    }

    //@After("cutPoint()")
    public void After() throws SQLException {

        System.out.println("最终通知");
        Connection connection = cUtils.getConnection();
        connection.setAutoCommit(true);
        connection.close();
    }

    //@AfterReturning("cutPoint()")
    public void AfterReturning() throws SQLException {
        System.out.println("后置通知");
        Connection connection = cUtils.getConnection();
        connection.commit();

    }

    //@AfterThrowing("execution(* cn.it.service.impl.*.*(..))")
    public void AfterThrowing() throws SQLException {
        System.out.println("异常通知");
        Connection connection = cUtils.getConnection();
        connection.rollback();
    }
    /**
     * 环绕通知:
     *     spring提供的一种通知类型,可以让程序员灵活的配置增强代码逻辑的执行过程
     *     具有拦截和放行的功能
     *        代码写法:和自定义动态代理方法中的增强逻辑类似
     *                            将前置通知,后置通知,异常通知,最终通知,全部都要定义在环绕通知中!
     *     1.ProceedingJoinPoint : 连接点对象
     *     2.proceed:内部可以调用被代理对象的方法
     *     3.返回值 : object   
     *               被代理对象方法的返回值
     */
    @Around("cutPoint()")
    public Object around(ProceedingJoinPoint pj) throws Throwable {
        Connection conn = cUtils.getConnection();
        Object proceed = null;

        try {
            System.out.println("前");
            conn.setAutoCommit(false);
            proceed = pj.proceed();
            System.out.println("后");
            conn.commit();
        } catch (Exception e) {
            System.out.println("异常");
            conn.rollback();
        } finally {
            System.out.println("最终");
            conn.setAutoCommit(true);
            conn.close();
        }

        return proceed;
    }

}

其他配置类的声明

package cn.it.config;

import java.beans.PropertyVetoException;

import javax.sql.DataSource;

import org.apache.commons.dbutils.QueryRunner;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;

import com.mchange.v2.c3p0.ComboPooledDataSource;


/**
 * 1.@Configuration:声明该类为配置类
 * 2.@PropertySource:读取property配置信息交给spring容器管理
 *    value属性为:文件名的类路径字符串 classpath:开头代表类路径,后面跟路径
 * 3.@Value("${jdbc.username}"):为成员变量赋值(基本类型值),用springEl表达式从spring容器中取值
 * 4.@Bean 调用该方法,将该方法的返回值交给spring容器管理 
 *    value属性,指定该对象在spring容器中的id为value的值
 * 5.@Qualifier:value属性指定从spring注入时,由通过类型查找,改为通过id查找,id为value属性的值 
 */
@Configuration
@PropertySource("classpath:jdbc.properties")
public class jdbcConfig {
    @Value("${jdbc.username}")
    private String User;
    @Value("${jdbc.password}")
    private String password;
    @Value("${jdbc.driver}")
    private String driver;
    @Value("${jdbc.url}")
    private String Url;
    @Bean("queryRunner")
    public QueryRunner getQueryRunner(@Qualifier("dataSource")DataSource ds) {
        return new QueryRunner(ds);
    }

    @Bean("dataSource")
    public DataSource getDataSource() {
        ComboPooledDataSource ds = new ComboPooledDataSource();
        ds.setUser(User);
        System.out.println("====================");
        ds.setPassword(password);
        try {
            ds.setDriverClass(driver);
        } catch (PropertyVetoException e) {
            e.printStackTrace();
        }
        ds.setJdbcUrl(Url);
        return ds;
    }

}

连接池工具类

package cn.it.utils;

import java.sql.Connection;
import java.sql.SQLException;

import javax.annotation.Resource;
import javax.sql.DataSource;
import javax.xml.crypto.Data;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
@Service
public class ConnectionUtils {
    @Autowired
    private  DataSource dataSource;

    private ThreadLocal<Connection> tl = new ThreadLocal<>();

    public Connection getConnection() {
        Connection conn = null;
        try {
            conn = tl.get();
            if(conn == null) {
                conn = dataSource.getConnection();
                tl.set(conn);
            }
        } catch (Exception e) {
        }
        return conn;
    }
}
阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页