面向切面的Spring<一>

来源:互联网 发布:order by sql 编辑:程序博客网 时间:2024/05/17 20:38

Spring提供了4种类型的AOP支持:

  • 基于代理的经典Spring AOP;
  • 纯POJO切面;
  • @AspectJ注解驱动的切面;
  • 注入式AspectJ切面(适用于Spring各个版本)

SpringAOP框架的一些必须要了解的关键知识

  • Spring通知是JAVA编写的

    Spring所创建的通知都是用标准的Java类编写的。因此可以用普通Java开发一样的IDE来开发切面。而且,定义通知所应用的切点通常会使用注解或在Spring 配置文件里采用XML来编写。

  • Spring在运行时通知对象

    通过在代理类中包裹切面,Spring在运行时期把切面织入到Spring管理的bean中。
    直到应用需要被代理的bean时,Spring才创建代理对象。如果使用的是ApplicationContext的话,在ApplicationContext从BeanFactory中加载所有的bean的时候,Spring才会被创建到代理对象。因为Spring运行时才创建代理对象,所以我们不需要特殊的编译器来织入SpringAOP的切面。

  • Spring只支持方法级别的连接点

    因为Spring基于动态代理,所以Spring只支持方法级别连接点。这与一些其他的AOP框架是不同的,例如AspectJ和JBoss,除了方法切点,它们还提供了字段和构造器接入点。Spring缺少对字段连接点的支持,无法让我们创建细粒度的通知,例如拦截对象字段的修改。而且它不支持构造器连接点,我们就无法再bean创建时应用通知。
    但是方法拦截可以满足绝大部分的需求。如果需要方法拦截之外的连接点拦截功能,我们可以利用AspectJ来补充SpringAOP的功能。


1. 注解方式实现AOP编程

步骤:
1) 先引入aop相关jar文件
2) bean.xml中引入aop名称空间
3) 开启aop注解
4) 使用注解
@Aspect 指定一个类为切面类
@Pointcut(“execution(* cn.itcast.e_aop_anno..(..))”) 指定切入点表达式
@Before(“pointCut_()”) 前置通知: 目标方法之前执行
@After(“pointCut_()”) 后置通知:目标方法之后执行(始终执行)
@AfterReturning(“pointCut_()”) 返回后通知: 执行方法结束前执行(异常不执行)
@AfterThrowing(“pointCut_()”) 异常通知: 出现异常时候执行
@Around(“pointCut_()”) 环绕通知: 环绕目标方法执行

下面是我项目中的maven配置

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">  <modelVersion>4.0.0</modelVersion>  <groupId>com.cyy</groupId>  <artifactId>Maven_01</artifactId>  <packaging>war</packaging>  <version>1.0-SNAPSHOT</version>  <name>Maven_01 Maven Webapp</name>  <url>http://maven.apache.org</url>  <dependencies>    <dependency>      <groupId>junit</groupId>      <artifactId>junit</artifactId>      <version>3.8.1</version>      <scope>test</scope>    </dependency>    <dependency>      <groupId>org.springframework</groupId>      <artifactId>spring-context</artifactId>      <version>4.2.6.RELEASE</version>    </dependency>    <dependency>      <groupId>org.springframework</groupId>      <artifactId>spring-test</artifactId>      <version>4.2.6.RELEASE</version>    </dependency>    <dependency>      <groupId>org.mockito</groupId>      <artifactId>mockito-core</artifactId>      <version>2.5.0</version>    </dependency>    <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->    <dependency>      <groupId>org.aspectj</groupId>      <artifactId>aspectjweaver</artifactId>      <version>1.8.9</version>    </dependency>    <!-- https://mvnrepository.com/artifact/aspectj/aspectjrt -->    <dependency>      <groupId>aspectj</groupId>      <artifactId>aspectjrt</artifactId>      <version>1.5.3</version>    </dependency>    <dependency>      <groupId>junit</groupId>      <artifactId>junit</artifactId>      <version>4.11</version>    </dependency>  </dependencies></project>
//1. IUserDao.java// 接口public interface IUserDao {    void save();}
//2. UserDao.java/** * 目标对象 * @author Jie.Yuan * */@Component   // 加入容器public class UserDao implements IUserDao{    @Override    public void save() {        System.out.println("-----核心业务:保存!!!------");     }}
//3. Aop.java  切面类@Component@Aspect  // 指定当前类为切面类public class Aop {    // 指定切入点表单式: 拦截哪些方法; 即为哪些类生成代理对象    @Pointcut("execution(* cn.itcast.e_aop_anno.*.*(..))")    public void pointCut_(){    }    // 前置通知 : 在执行目标方法之前执行@Before("pointCut_()")    public void begin(){        System.out.println("开始事务/异常");    }    // 后置/最终通知:在执行目标方法之后执行  【无论是否出现异常最终都会执行】    @After("pointCut_()")    public void after(){        System.out.println("提交事务/关闭");    }    // 返回后通知: 在调用目标方法结束后执行 【出现异常不执行】    @AfterReturning("pointCut_()")    public void afterReturning() {        System.out.println("afterReturning()");    }    // 异常通知: 当目标方法执行异常时候执行此关注点代码    @AfterThrowing("pointCut_()")    public void afterThrowing(){        System.out.println("afterThrowing()");    }    // 环绕通知:环绕目标方式执行    @Around("pointCut_()")    public void around(ProceedingJoinPoint pjp) throws Throwable{        System.out.println("环绕前....");        pjp.proceed();  // 执行目标方法        System.out.println("环绕后....");    }}
//4. bean.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:p="http://www.springframework.org/schema/p"    xmlns:context="http://www.springframework.org/schema/context"    xmlns:aop="http://www.springframework.org/schema/aop"    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/aop        http://www.springframework.org/schema/aop/spring-aop.xsd">    <!-- 开启注解扫描 -->    <context:component-scan base-package="cn.itcast.e_aop_anno"></context:component-scan>    <!-- 开启aop注解方式 -->    <aop:aspectj-autoproxy></aop:aspectj-autoproxy></beans>
//App.javapublic class App {    ApplicationContext ac =         new ClassPathXmlApplicationContext("cn/itcast/e_aop_anno/bean.xml");    // 目标对象有实现接口,spring会自动选择“JDK代理”    @Test    public void testApp() {        IUserDao userDao = (IUserDao) ac.getBean("userDao");        System.out.println(userDao.getClass());        userDao.save();    }    // 目标对象没有实现接口, spring会用“cglib代理”    @Test    public void testCglib() {        OrderDao orderDao = (OrderDao) ac.getBean("orderDao");        System.out.println(orderDao.getClass());        orderDao.save();    }}

2. XML方式实现AOP编程

Xml实现aop编程:
1) 引入jar文件 【aop 相关jar, 4个】
2) 引入aop名称空间
3)aop 配置
* 配置切面类 (重复执行代码形成的类)
* aop配置
拦截哪些方法 / 拦截到方法后应用通知代码

<?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:p="http://www.springframework.org/schema/p"    xmlns:context="http://www.springframework.org/schema/context"    xmlns:aop="http://www.springframework.org/schema/aop"    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/aop        http://www.springframework.org/schema/aop/spring-aop.xsd">    <!-- dao 实例 -->    <bean id="userDao" class="cn.itcast.f_aop_xml.UserDao"></bean>    <bean id="orderDao" class="cn.itcast.f_aop_xml.OrderDao"></bean>    <!-- 切面类 -->    <bean id="aop" class="cn.itcast.f_aop_xml.Aop"></bean>    <!-- Aop配置 -->    <aop:config>        <!-- 定义一个切入点表达式: 拦截哪些方法 -->        <aop:pointcut expression="execution(* cn.itcast.f_aop_xml.*.*(..))" id="pt"/>        <!-- 切面 -->        <aop:aspect ref="aop">            <!-- 环绕通知 -->            <aop:around method="around" pointcut-ref="pt"/>            <!-- 前置通知: 在目标方法调用前执行 -->            <aop:before method="begin" pointcut-ref="pt"/>            <!-- 后置通知: -->            <aop:after method="after" pointcut-ref="pt"/>            <!-- 返回后通知 -->            <aop:after-returning method="afterReturning" pointcut-ref="pt"/>            <!-- 异常通知 -->            <aop:after-throwing method="afterThrowing" pointcut-ref="pt"/>        </aop:aspect>    </aop:config></beans>  

2. 切入点表达式

切入点表达式,
可以对指定的“方法”进行拦截; 从而给指定的方法所在的类生层代理对象。

<?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:p="http://www.springframework.org/schema/p"    xmlns:context="http://www.springframework.org/schema/context"    xmlns:aop="http://www.springframework.org/schema/aop"    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/aop        http://www.springframework.org/schema/aop/spring-aop.xsd">    <!-- dao 实例 -->    <bean id="userDao" class="cn.itcast.g_pointcut.UserDao"></bean>    <bean id="orderDao" class="cn.itcast.g_pointcut.OrderDao"></bean>    <!-- 切面类 -->    <bean id="aop" class="cn.itcast.g_pointcut.Aop"></bean>    <!-- Aop配置 -->    <aop:config>        <!-- 定义一个切入点表达式: 拦截哪些方法 -->        <!--<aop:pointcut expression="execution(* cn.itcast.g_pointcut.*.*(..))" id="pt"/>-->        <!-- 【拦截所有public方法】 -->        <!--<aop:pointcut expression="execution(public * *(..))" id="pt"/>-->        <!-- 【拦截所有save开头的方法 】 -->        <!--<aop:pointcut expression="execution(* save*(..))" id="pt"/>-->        <!-- 【拦截指定类的指定方法, 拦截时候一定要定位到方法】 -->        <!--<aop:pointcut expression="execution(public * cn.itcast.g_pointcut.OrderDao.save(..))" id="pt"/>-->        <!-- 【拦截指定类的所有方法】 -->        <!--<aop:pointcut expression="execution(* cn.itcast.g_pointcut.UserDao.*(..))" id="pt"/>-->        <!-- 【拦截指定包,以及其自包下所有类的所有方法】 -->        <!--<aop:pointcut expression="execution(* cn..*.*(..))" id="pt"/>-->        <!-- 【多个表达式】 -->        <!--<aop:pointcut expression="execution(* cn.itcast.g_pointcut.UserDao.save()) || execution(* cn.itcast.g_pointcut.OrderDao.save())" id="pt"/>-->        <!--<aop:pointcut expression="execution(* cn.itcast.g_pointcut.UserDao.save()) or execution(* cn.itcast.g_pointcut.OrderDao.save())" id="pt"/>-->        <!-- 下面2个且关系的,没有意义 -->        <!--<aop:pointcut expression="execution(* cn.itcast.g_pointcut.UserDao.save()) &amp;&amp; execution(* cn.itcast.g_pointcut.OrderDao.save())" id="pt"/>-->        <!--<aop:pointcut expression="execution(* cn.itcast.g_pointcut.UserDao.save()) and execution(* cn.itcast.g_pointcut.OrderDao.save())" id="pt"/>-->        <!-- 【取非值】 -->        <!--<aop:pointcut expression="!execution(* cn.itcast.g_pointcut.OrderDao.save())" id="pt"/>-->        <aop:pointcut expression=" not execution(* cn.itcast.g_pointcut.OrderDao.save())" id="pt"/>        <!-- 切面 -->        <aop:aspect ref="aop">            <!-- 环绕通知 -->            <aop:around method="around" pointcut-ref="pt"/>        </aop:aspect>    </aop:config></beans>    

3. Spring对jdbc支持

使用步骤:
1)引入jar文件
spring-jdbc-3.2.5.RELEASE.jar
spring-tx-3.2.5.RELEASE.jar
2) 优化

//UserDao.javapackage jdbc;import org.springframework.jdbc.core.JdbcTemplate;import org.springframework.jdbc.core.RowMapper;import javax.sql.DataSource;import java.sql.ResultSet;import java.sql.SQLException;import java.util.List;/** * Created by Administrator on 2017/2/3. */public class UserDao {    //IOC容器注入    private DataSource dataSource;    public void setDataSource(DataSource dataSource){        this.dataSource = dataSource;    }    public void save(){        String sql = "insert into t_dept(deptName) values('test')";        //使用jdbc模板工具类简化jdbc操作        JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);        jdbcTemplate.update(sql);    }    public Dept findById(int id){        String sql = "select * from t_dept";        JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);        //List<Map<String,Object>> list = jdbcTemplate.queryForList(sql);        List<Dept> list = jdbcTemplate.query(sql, new RowMapper<Dept>() {            //如何封装一行数据            @Override            public Dept mapRow(ResultSet resultSet, int i) throws SQLException {                Dept dept = new Dept();                dept.setDeptId(resultSet.getInt("deptId"));                dept.setDeptName(resultSet.getString("deptName"));                return dept;            }        });        System.out.println(list);        return null;    }}
//Dept.javapackage jdbc;/** * Created by Administrator on 2017/2/3. */public class Dept {    private int deptId;    private String deptName;    public int getDeptId() {        return deptId;    }    public void setDeptId(int deptId) {        this.deptId = deptId;    }    public String getDeptName() {        return deptName;    }    public void setDeptName(String deptName) {        this.deptName = deptName;    }    @Override    public String toString() {        return "Dept{" +                "deptId=" + deptId +                ", deptName='" + deptName + '\'' +                '}';    }}
//bean.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:p="http://www.springframework.org/schema/p"    xmlns:context="http://www.springframework.org/schema/context"    xmlns:aop="http://www.springframework.org/schema/aop"    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/aop        http://www.springframework.org/schema/aop/spring-aop.xsd">    <!-- 1. 数据源对象: C3P0连接池 -->    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">        <property name="driverClass" value="com.mysql.jdbc.Driver"></property>        <property name="jdbcUrl" value="jdbc:mysql:///hib_demo"></property>        <property name="user" value="root"></property>        <property name="password" value="123456"></property>        <property name="initialPoolSize" value="3"></property>        <property name="maxPoolSize" value="10"></property>        <property name="maxStatements" value="100"></property>        <property name="acquireIncrement" value="2"></property>    </bean>    <!-- 2. 创建JdbcTemplate对象 -->    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">        <property name="dataSource" ref="dataSource"></property>    </bean>    <!-- dao 实例 -->    <bean id="userDao" class="jdbc.UserDao">        <property name="dataSource" ref="dataSource"></property>    </bean></beans>      
//测试类public class App {    //容器对象    ApplicationContext ac = new ClassPathXmlApplicationContext("jdbc/bean.xml");    @Test    public void testApp(){        UserDao dao = (UserDao) ac.getBean("userDao");        //dao.save();        dao.findById(2);    }}

别忘了在数据库中建相应的数据库、表,注意字段与实体类之间的对应。

0 0
原创粉丝点击