JAVA Web学习(25)___第19章Spring核心之AOP

第19章Spring核心之AOP

19.1 AOP概述

AOP:Aspect Oriented Programming,中文翻译为”面向切面编程“。面向切面编程是一种编程范式,它作为OOP面向对象编程的一种补充,用于处理系统中分布于各个模块的横切关注点,比如事务管理、权限控制、缓存控制、日志打印等等。AOP采取横向抽取机制,取代了传统纵向继承体系的重复性代码
AOP把软件的功能模块分为两个部分:核心关注点和横切关注点。业务处理的主要功能为核心关注点,而非核心、需要拓展的功能为横切关注点。AOP的作用在于分离系统中的各种关注点,将核心关注点和横切关注点进行分离
使用AOP有诸多好处,如:
1.集中处理某一关注点/横切逻辑
2.可以很方便的添加/删除关注点
3.侵入性少,增强代码可读性及可维护性

19.1.1 了解AOP

AOP的术语

  • 1.Join point(连接点)
    Spring 官方文档的描述:

A point during the execution of a program, such as the execution of a method or the handling of an exception. In Spring AOP, a join point always represents a method execution.

程序执行过程中的一个点,如方法的执行或异常的处理。在Spring AOP中,连接点总是表示方法的执行。通俗的讲,连接点即表示类里面可以被增强的方法

  • 2.Pointcut(切入点)

Pointcut are expressions that is matched with join points to determine whether advice needs to be executed or not. Pointcut uses different kinds of expressions that are matched with the join points and Spring framework uses the AspectJ pointcut expression language

切入点是与连接点匹配的表达式,用于确定是否需要执行通知。切入点使用与连接点匹配的不同类型的表达式,Spring框架使用AspectJ切入点表达式语言。我们可以将切入点理解为需要被拦截的Join point

  • 3.Advice(增强/通知)
    所谓通知是指拦截到Joinpoint之后所要做的事情就是通知,通知分为前置通知、后置通知、异常通知、最终通知和环绕通知(切面要完成的功能)
  • 4.Aspect(切面)
    Aspect切面表示Pointcut(切入点)和Advice(增强/通知)的结合

19.1.2 AOP的简单实现

  • 1.创建web程序,导入cglib-2.2.jar、commons-logging-1.0.4.jar、spring-aop-3.2.0.RELEASE.jar、spring-core-3.2.0.RELEASE.jar
    spring-beans-3.2.0.RELEASE.jar、spring-context-3.2.0.RELEASE.jar、spring-context-support-3.2.0.RELEASE.jar、spring-webmvc.jar、spring.jar
  • 2.创建Target.java类,它是被代理的目标对象,其中有一个execute()方法,它可以专注于自己的智能,此处使用AOP对execute()方法做日子输出
public class Target {
    //程序执行的方法
    public void execute(String name){
        System.out.println("程序开始执行--"+name);
    }
}
  • 3.创建通知 LoggerExecute.java
public class LoggerExecute implements MethodInterceptor{

    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        before();//执行前置通知
        invocation.proceed();
        return null;
    }

    private void before() {
    System.out.println("程序开始执行!");
        
    }

}
  • 4.创建代理操作类,Manger.java
public class Manger {
    //此处使用junit测试
    @Test
    public void test(){
    Target target=new Target();             //创建目标对象
    ProxyFactory proxyFactory=new ProxyFactory();
    proxyFactory.addAdvice(new LoggerExecute());
    proxyFactory.setTarget(target);
    Target target2=(Target) proxyFactory.getProxy();
    target2.execute("AOP的简单实现");//代理执行execute()方法
    }
}

执行后控制台输出

程序开始执行!
程序开始执行--AOP的简单实现

19.2 Spring的切入点

19.2.1 静态切入点与动态切入点

  • 静态切入点
    静态往往意味着不变,例如一个对象的方法签名是固定不变的,无论在程序的任何位置调用,方法名都不会改变,静态切入点可以为对象的方法签名,例如在某个对象调用了execute()方法时,该方法就可以是静态切入点,静态切入点需要在配置文件时指定,关键配置如下:
    <bean id="pointcutAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
    <property name="advice">
        <ref bean="MyAdvisor"/>//指定通知
    </property> 
    <property  name="patterns">
        <list>
            <value>.*getConn*.</value>//指定所有以getConn开头的方法名都是切入点
            <value>.*closeConn*.</value>
        </list>
    </property>
    </bean>
  • 动态切入点
    动态切入点是相对于静态切入点的。

19.2.2 深入静态切入点

19.2.3 深入切入点底层

19.2.4 Spring中其他切入点

19.3 Aspect对AOP的支持

19.3.1 了解Aspect

19.3.2 Spring中的Aspect

19.3.3 DefaultPointcutAdvisor切入点配置器

19.3.4 NameMatchMethodPointcutAdvisor切入点配置

19.4 Spring持久化

19.4.1 DAO模式介绍

1 Spring DAO的概念
什么是DAO
DAO(Data Access Object)是用于访问数据的对象,虽然在大多数情况下将数存在数据库中,但这并不是唯一的选择,也可以将数据存储到文件中或LDAP中。DAO不但屏蔽了数据存储的最终介质的不同,也屏蔽了具体的实现技术的不同。提供DAO层的抽象可以带来一些好处:可以很容易地构造模拟对象,方便单元测试的开展;在使用切面时会有更多的选择,既可以使用JDK动态代理,又可以使用 CGLib动态代理。

Spring DAO的内容
*Spring对多个持久化技术提供了集成支持,包括 Hibernate、 MyBatis、JPA、JDO;
*Spring提供一个简化JDBC API操作的Spring JDBC框架。
*Spring面向DAO制定了一个通用的异常体系,屏蔽具体持久化技术的异常,使业务层和具体的持久化技术实现解耦。
*Spring提供了模板类简化各种持久化技术的使用

19.4.2 Spring的DAO理念

  • 1.创建web工程,引入如下jar包commons-logging-1.0.4.jar、mysql-connector-java-5.1.38.jar、spring-aop-3.2.0.RELEASE.jar、spring-web.jar、spring-webmvc.jar、spring.jar
  • 2.实体类,Book.java
public class Book {
    private int id;
    private String name;
    private double price;
    private int bookCount;
    private String author;
    ...省略setter()和getter()方法
    }
  • 3.创建接口类
public interface BookDaoImpl {
    public void inserBook(Book book);//添加信息
}
  • 4.编写实现BookDaoImpl接口的BookDao类并实现方法

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

import javax.sql.DataSource;
import com.hwp.spring.bean.Book;
public class BookDao implements BookDaoImpl{
    private DataSource dataSource;//注入DataSource
    
    public DataSource getDataSource() {
        return dataSource;
    }

    public void setDataSource(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    @Override
    public void inserBook(Book book) {
        
        String name = book.getName();//获取书籍名字
        double price = book.getPrice();//获取价格
        int bookCount = book.getBookCount();//获取数量
        String author = book.getAuthor();//或者作者
        
        
        Connection connection = null ;//定义Connection
        Statement statement = null;//定义Statement
         try {
            connection = dataSource.getConnection();//获取数据库连接
             statement = connection.createStatement();
             statement.execute("INSERT INTO book_info (name,price,bookCount,author) " 
                      + "VALUES('"+ name + "','" + price +"','"+bookCount+"','"+author+ "')");//添加数据的SQL语句
        } catch (SQLException e) {
            e.printStackTrace();
            System.out.println(e.toString());
        }
         finally {
             if(statement != null) {
                 try {
                     statement.close();//关闭Statement对象
                 }   
                 catch(SQLException e) {
                     e.printStackTrace();
                 }
             }
             if(connection != null) {
                 try {
                     connection.close();//关闭数据库连接
                 }
                 catch(SQLException e) {
                     e.printStackTrace();
                 }
             }
         }
        
    }

}

  • 5.配置applicationContext.xml,存放在源码目录下,即src目录下
<?xml version="1.0" encoding="UTF-8"?>
<beans
    xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
    <!-- 配置数据源 -->
    <bean id="dataSource"
        class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName">
            <value>com.mysql.jdbc.Driver</value>
        </property>
        <property name="url">
        <!-- 避免乱码 需要这样?characterEncoding=utf-8-->
            <value>jdbc:mysql://localhost:3306/book?characterEncoding=utf-8
            </value>
        </property>
        <property name="username">
            <value>root</value>
        </property>
        <property name="password">
            <value>hwp123456</value>
        </property>
    </bean>
    <!-- 为UserDAO注入数据源 -->
    <bean id="bookDAO" class="com.hwp.spring.dao.BookDao">
        <property name="dataSource">
            <ref local="dataSource"/>
        </property>
    </bean>
</beans>
  • 6.编写manger.java操作类
public class Manger {
    //使用junit测试
    @Test
public  void main() {
    Resource resource=new ClassPathResource("applicationContext.xml");
    BeanFactory beanFactory=new XmlBeanFactory(resource);
    Book book=new  Book();
    book.setAuthor("中文测试");
    book.setBookCount(60);
    book.setName("我是作者");
    book.setPrice(58.0);
    BookDao bookDao= (BookDao) beanFactory.getBean("bookDAO");
    bookDao.inserBook(book);
    System.out.println("添加数据成功");
}
}

运行后,就能往数据库添加一条数据。

19.4.3 事务应用的管理

  • 编程式事务管理
  • 1.创建web工程,引入如下jar包commons-logging-1.0.4.jar、mysql-connector-java-5.1.38.jar、spring-aop-3.2.0.RELEASE.jar、spring-web.jar、spring-webmvc.jar、spring.jar
  • 2.配置applicationContext.xml,存放在源码目录下,即src目录下
<?xml version="1.0" encoding="UTF-8"?>
<beans
    xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
    <!-- 配置数据源 -->
    <bean id="dataSource"
        class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName">
            <value>com.mysql.jdbc.Driver</value>
        </property>
        <property name="url">
            <value>jdbc:mysql://localhost:3306/db_database13
            </value>
        </property>
        <property name="username">
            <value>root</value>
        </property>
        <property name="password">
            <value>111</value>
        </property>
    </bean>
    <!-- 定义TransactionTemplate模板 -->
    <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
        <property name="transactionManager">
            <ref bean="transactionManager"/>
        </property>
        <property name="propagationBehaviorName">
            <value>PROPAGATION_REQUIRED</value>
        </property>
    </bean>
    <!-- 定义事务管理器 -->
    <bean id="transactionManager"
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource">
            <ref bean="dataSource" />
        </property>
    </bean>
    <!-- 为TransactionExample注入数据源 、事务管理器、TransactionTemplate模板-->
    <bean id="transactionExample"
        class="com.mr.transaction.TransactionExample">
        <property name="dataSource">
            <ref bean="dataSource" />
        </property>
        <property name="transactionManager">
            <ref bean="transactionManager" />
        </property>
        <property name="transactionTemplate">
            <ref bean="transactionTemplate"/>
        </property>
    </bean>
</beans>
  • 3.创建类TransationExample,定义数据添加的方法,在方法中执行两次数据库添加的操作,并用事务对操作进行保护。

public class TransactionExample {
    DataSource dataSource;//注入数据源
    PlatformTransactionManager transactionManager;//注入事务管理器
    TransactionTemplate transactionTemplate;//注入TransactionTemplate模板
   ...//省略setter()和getter()方法
    public PlatformTransactionManager getTransactionManager() {
        return transactionManager;
    }
    public void setTransactionManager(PlatformTransactionManager transactionManager) {
        this.transactionManager = transactionManager;
    }
    public TransactionTemplate getTransactionTemplate() {
        return transactionTemplate;
    }
    public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
        this.transactionTemplate = transactionTemplate;
    }
    public void transactionOperation() {
        transactionTemplate.execute(new TransactionCallback() {
            public Object doInTransaction(TransactionStatus status) {
                Connection conn = DataSourceUtils.getConnection(dataSource);//获得数据库连接
                try {
                    Statement stmt = conn.createStatement();
                    //执行两次添加方法
                    stmt.execute("insert into tb_user(name,age,sex) values('小强','26','男')");
                    int a=0;//制造异常测试事务是否配置成功
                    a=9/a;
                    stmt.execute("insert into tb_user(name,age,sex) values('小红','22','女')");
                    System.out.println("操作执行成功!");
                } catch (Exception e) {
                    transactionManager.rollback(status);//事务回滚
                    System.out.println("操作执行失败,事务回滚!");
                    System.out.println("原因:"+e.getMessage());
                }
                return null;
            }
        });
    }
}

  • 4.创建Manger.java,
public class Manger {
    public static void main(String[] args) {
        Resource resource = new ClassPathResource("applicationContext.xml");            //装载配置文件
        BeanFactory factory = new XmlBeanFactory(resource);
        TransactionExample transactionExample = (TransactionExample) factory.getBean("transactionExample");//获取UserDAO
        transactionExample.transactionOperation();//执行添加方法
    }
}

编码方式实现事务管理(代码演示为JDBC事务管理)
Spring实现编程式事务,依赖于2大类,分别是上篇文章提到的PlatformTransactionManager,与模版类TransactionTemplate(推荐使用)。

  • 声明式事务管理
    声明式事务实现方式主要有2种,一种为通过使用Spring的<tx:advice>定义事务通知与AOP相关配置实现,另为一种通过@Transactional实现事务管理实现

19.4.4 应用JdbcTemplate操作数据库

Spring对数据库的操作在jdbc上面做了深层次的封装,使用spring的注入功能,可以把DataSource注册到JdbcTemplate之中。
JdbcTemplate位于中spring-jdbc-3.2.0.RELEASE.jar。其全限定命名为org.springframework.jdbc.core.JdbcTemplate。要使用JdbcTemlate还需一个spring-tx-3.2.0.RELEASE.jar这个包包含了一下事务和异常控制
JdbcTemplate主要提供以下五类方法:

  • execute方法:可以用于执行任何SQL语句,一般用于执行DDL语句;
  • update方法及batchUpdate方法:update方法用于执行新增、修改、删除等语句;batchUpdate方法用于执行批处理相关语句;
  • query方法及queryForXXX方法:用于执行查询相关语句;
  • call方法:用于执行存储过程、函数相关语句。

19.4.5 与Hibernate整合

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容