面向切面的Spring<一>

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.java
public 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.java
package 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.java
package 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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值