Spring入门配置(二) - AOP

一、AOP简介

  AOP:Aspect Oriented Programming,面向切面编程,通过预编译方式和动态代理实现程序功能的统一维护的一种技术。利用AOP对业务逻辑各个部分进行抽取隔离,从而使逻辑各部分间的耦合度降低,提高程序的可重用性,提高开发效率。

  1. JDK动态代理和Cglib动态代理

    • JDK动态代理(基于接口)
      Target target = new Target(); //创建目标对象
      //创建代理对象,Target implements TargetInterface TargetInterface proxy = (TargetInterface) Proxy.newProxyInstance(target.getClass().getClassLoader(),
        target.getClass().getInterfaces(),new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("前置增强代码..."); Object invoke = method.invoke(target, args);//反射方法对象,即要执行的目标对象 System.out.println("后置增强代码..."); return invoke; } });
    • Cglib动态代理(基于父类)
      Target target = new Target(); //创建目标对象
      Enhancer enhancer = new Enhancer();   //创建增强器
      enhancer.setSuperclass(Target.class); //设置父类
      enhancer.setCallback(new MethodInterceptor() { //设置回调
          @Override
          public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
          System.out.println("前置代码增强....");
          Object invoke = method.invoke(target, objects);
          System.out.println("后置代码增强....");
          return invoke;
          }
      });
      Target proxy = (Target) enhancer.create(); //创建代理对象
  2.  AOP相关术语

    Target(目标对象)

    代理的目标对象

    Proxy (代理) 一个类被 AOP 织入增强后,就产生一个结果代理类
    Joinpoint(连接点) 那些可以被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点
    Pointcut(切入点) 对哪些 Joinpoint 进行拦截的定义
    Advice(通知/ 增强) 拦截到 Joinpoint 之后所要做的事情就是通知

    Aspect(切面)

    是切入点和通知(引介)的结合
    Weaving(织入) 把增强应用到目标对象来创建新的代理对象的过程。spring采用动态代理织入,而AspectJ采用编译期织入和类装载期织入

 

二、基于XML的AOP开发

  1. 步骤:

    1. 导包:aspectjweaver & spring-context
    2. 创建目标类和目标接口Target(创建Pointcut)
    3. 创建切面类Aspect(创建Advice)
    4. 将Target和Aspect注入Spring(配置Spring配置文件)
    5. 配置织入关系,首先需要进行AOP命名空间和约束路径的配置
      命名空间:
      xmlns:aop="http://www.springframework.org/schema/aop"
      约束路径:
      http://www.springframework.org/schema/aop
      http://www.springframework.org/schema/aop/spring-aop.xsd

      配置织入关系

      <aop:config>
      <!--引用myAspect的Bean为切面对象-->
          <aop:aspect ref="myAspect">
              <aop:pointcut id="myPointcut" expression="execution(* GroupId.ArtifactId.aop.*.*(..))"/> <!--抽取表达式,此处主要配置 哪个位置的哪些方法-->
         <!--通知的配置语法:<aop:通知类型 method=“切面类中方法名” pointcut=“切点表达式">,目标类在包下-->
         <!--逻辑:切点被切面类的通知增强,主要明确:哪个位置的哪些方法被进行了哪些增强-->
      <aop:before method="before" pointcut-ref="myPointcut"></aop:before> <!--此处配置 进行了哪些增强--> </aop:aspect> </aop:config>
  2. 详解:

    1. 表达式语句:execution([修饰符] 返回值类型 包名.类名.方法名(参数))
      • 访问修饰符可以省略
      • 返回值类型、包名、类名、方法名可以使用星号 * 代表任意
      • 包名与类名之间一个点 . 代表当前包下的类, 两个点 .. 表示当前包及其子包下的类
      • 参数列表可以使用两个点 .. 表示任意个数,任意类型的参数列表
    2. 通知类型

三、基于注解的AOP

  1.  @Aspect 标注切面

  2.  方法前声明通知类型,会抽取表达式语句

    通知的配置语法:@通知注解(“切点表达式")

    表达式语句的抽取:抽取方式是在切面内定义方法,在该方法上使用@Pointcut注解定义切点表达式,然后在在增强注解中进行引用。

    @Component("myAspect")
    @Aspect
    public class MyAspect {
        @Before("MyAspect.myPoint()")
        public void before(){
            System.out.println("前置代码增强.....");
        }
        @Pointcut("execution(* 全限定名aop.*.*(..))")
        public void myPoint(){}
    }
  3.  在配置文件中开启组件扫描和 AOP 的自动代理

    <!--组件扫描-->
    <context:component-scan base-package="包aop全限定名"/>
    <!--aop的自动代理-->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

四、AOP应用-->声明式事务控制

  1. 基于XML

       需要引入tx命名空间

    xmlns:tx="http://www.springframework.org/schema/tx"
    http://www.springframework.org/schema/tx
    http://www.springframework.org/schema/tx/spring-tx.xsd
    1. 常用对象

      PlatformTransactionManager 接口是 spring 的事务管理器,它里面提供了我们常用的操作事务的方法。
      PlatformTransactionManager 是接口类型,不同的 Dao 层技术则有不同的实现类,例如:Dao 层技术是jdbc 或 mybatis 时:org.springframework.jdbc.datasource.DataSourceTransactionManager Dao 层技术是hibernate时:org.springframework.orm.hibernate5.HibernateTransactionManager
      TransactionDefinition 是事务的定义信息对象
      TransactionStatus 提供事务具体的运行状态

    2. 配置事务增强

      <!--平台事务管理器-->
      <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
          <property name="dataSource" ref="dataSource"></property> <!--事务方法通过connection对象调用-->
      </bean>
      <!--事务增强配置-->
      <tx:advice id="txAdvice" transaction-manager="transactionManager">
          <tx:attributes>
              <tx:method name="*"/>
          </tx:attributes>
      </tx:advice>
    3. 配置事务AOP织入

      <!--事务的aop增强-->
      <aop:config>
          <aop:pointcut id="myPointcut" expression="execution(* 全限定名.service.impl.*.*(..))"/>
         <!--事务比较特殊,因为内部事务增强已经定义好了(创建回滚提交),此处详细配置哪个位置的哪些方法需要被增强-->
      <aop:advisor advice-ref="txAdvice" pointcut-ref="myPointcut"></aop:advisor> </aop:config>

      tx:method 代表切点方法的事务参数的配置,即 TransactionDefinition,其他属性如下:

      • name:切点方法名称
      • isolation:事务的务的传播行为
      • timeout:超时时间
      • read-only:是否只读
  2. 基于注解

    1. 编写 AccoutDao
      //转账事务
      @Repository("accountDao")
      public class AccountDaoImpl implements AccountDao {
          @Autowired
          private JdbcTemplate jdbcTemplate;
          public void out(String outMan, double money) {
              jdbcTemplate.update("update account set money=money-? where name=?",money,outMan);
          }
          public void in(String inMan, double money) {
             jdbcTemplate.update("update account set money=money+? where name=?",money,inMan);
          }
      }
    2. 编写 AccoutService
      @Service("accountService")
      @Transactional
      public class AccountServiceImpl implements AccountService {
          @Autowired
          private AccountDao accountDao;
          @Transactional(isolation = Isolation.READ_COMMITTED,propagation = Propagation.REQUIRED)
          public void transfer(String outMan, String inMan, double money) {
              accountDao.out(outMan,money);
              // int i = 1/0; //发生异常
              accountDao.in(inMan,money);
          }
      }
    3. 编写 applicationContext.xml 配置文件,开启事务的注解驱动
      <!--组件扫描-->
      <context:component-scan base-package="com.itheima"/>
      <!--事务的注解驱动-->
      <tx:annotation-driven/>
posted @ 2019-07-11 10:02  想学好Java  阅读(221)  评论(0编辑  收藏  举报