菜鸟的成长之路——基于Schema的aop

  前面对于AOP的配置太令人抓狂,代码量实在是太大,反而失去了spring一直追求的简洁。但是spring给我们敞开了新的大门,他给我们提供了基于Schema配置的方法,现在将增强和切点的配置完全放在了Schema的xml文件中,切点和增强从xml中提取出来,那切面变成了真正的POJO了。

  因为Schema配置方式,让然脱离不了Aspectj,所以我们需要先导入Aspect Weaver 这个jar包。

1、那基于Schema的AOP简单例子怎么写?

  我们首先使用一个前值增强来实现一个简单的基于Schema的AOP,代码如下:
Lecturer.java(目标类)

package com.spring.test;

/**
 * 讲师类,具有上课方法
 * @author beijingduanluo
 *
 */
public class Lecturer {
    public void classBegin(){
        System.out.println("讲师传授新技术,同学们讨论很激烈!");
    }
}

LecturerAdvice.java(增强类)

package com.spring.test;

public class LecturerAdvice{
    /**
     * 前置增强的横切逻辑
     */
    public void beforeAdvice() {
        System.out.println("这是一个前置增强。");
    }

}

ApplicationContext.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:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:context="http://www.springframework.org/schema/context"
    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-4.3.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">

    <!-- 配置目标类 -->
    <bean id="lecturer" class="com.spring.test.Lecturer"></bean>
    <!-- 配置增强类 -->
    <bean id="advice" class="com.spring.test.LecturerAdvice"></bean>

    <!-- 开始aop配置 -->
    <aop:config>
        <!-- 配置切点 -->
        <aop:pointcut expression="execution(public void classBegin())" id="pointcut"/>
        <aop:aspect ref="advice">
            <aop:before method="beforeAdvice" pointcut-ref="pointcut"/>
        </aop:aspect>
    </aop:config>


</beans>

SpringTest.java(测试类)

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.spring.test.Lecturer;

public class SpringTest{

    public static void main(String[] args){
        ApplicationContext content = new ClassPathXmlApplicationContext("applicationcontext.xml");
        Lecturer lecturer = (Lecturer) content.getBean("lecturer");
        lecturer.classBegin();
    }
}

控制台

这是一个前置增强。
讲师传授新技术,同学们讨论很激烈!

  这样一个简单的前置增强就完成了,我们来分析一下这个配置文件。
  首先我们配置了目标类的bean和增强类的bean,这个不需要累述,我们再看一下配置文件里的标签。
  我们在配置文件里引入了aop命名空间,使用<aop:config>开始了一个切面的配置,在这个标签里面有两个属性,分别是expose-proxyproxy-target-class,前者的默认值为false,意味着代理类外界不可见,但是我们可以像上面测试类那样使用getbean方法获取代理类,这个属性一般很少见到。后者的值默认为false,意味着spring使用jdk动态代理方式,为true的时候意味着sring使用CGLib动态代理,没有特殊情况不建议修改,让spring自己选择代理方式。
  在<aop:config>标签内部,我们使用<aop:pointcut>标签配置切点,然后在以后方便引用,在这里我们可以不单独配置切点,在增强的pointcut属性配置切点也可以,我们后面还会提到。这个标签里有两个属性,id和expression,前者是这个标签的唯一标识,后者表明切点,值的格式为
target(com.spring.test.Lecturer) and execution(public void classBegin())
target标识的小括号内是类的全限定名,execution标识的小括号内是方法全限定名,如果有参数,在小括号内写明参数的类型列表即可。

  仍然是<app:config>标签内部,<aop:aspect>标签配置一个切面,有三个属性:id、order、ref。id是标签的唯一标识符,order决定了多个切面的执行顺序,值越大,越靠后执行,ref引入了增强类的bean。

  在<aop:aspect>标签内部配置连增强,<aop:before>是前置增强的标签,属性id是唯一标识符,point属性可以直接写切点表达式,point-ref属性可以引入切点标签,arg-names属性可以将目标方法的参数传递到增强的参数,但是要将切点表达式写成target(com.spring.test.Lecturer) and execution(public void classBegin(..)) and args(b),这样一个简单的前置增强就写完了。

2、如何基于Schema写一个后置增强的例子?

  有了上面的经验,我们写出如下代码:

Lecturer.java(目标类)

package com.spring.test;

/**
 * 讲师类,具有上课方法
 * @author beijingduanluo
 *
 */
public class Lecturer {
    public void classBegin(){
        System.out.println("讲师传授新技术,同学们讨论很激烈!");
    }
}

LecturerAdvice.java(增强类)

package com.spring.test;

public class LecturerAdvice{
    /**
     * 后置增强的横切逻辑
     */
    public void afterAdvice() {
        System.out.println("这是一个后置增强。");
    }

}

ApplicationContext.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:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:context="http://www.springframework.org/schema/context"
    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-4.3.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">

    <!-- 配置目标类 -->
    <bean id="lecturer" class="com.spring.test.Lecturer"></bean>
    <!-- 配置增强类 -->
    <bean id="advice" class="com.spring.test.LecturerAdvice"></bean>

    <!-- 开始aop配置 -->
    <aop:config>
        <!-- 配置切点 -->
        <aop:pointcut expression="target(com.spring.test.Lecturer) and execution(public void classBegin())" id="pointcut"/>
        <aop:aspect ref="advice">
            <aop:after-returning method="afterAdvice" pointcut-ref="pointcut"/>
        </aop:aspect>
    </aop:config>


</beans>

SpringTest.java(测试类)

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.spring.test.Lecturer;

public class SpringTest{

    public static void main(String[] args){
        ApplicationContext content = new ClassPathXmlApplicationContext("applicationcontext.xml");
        Lecturer lecturer = (Lecturer) content.getBean("lecturer");
        lecturer.classBegin();
    }
}

控制台

讲师传授新技术,同学们讨论很激烈!
这是一个后置增强。

  这样一个后置增强就写完了,我们着重看一下配置文件的增强的配置。<aop:after-returning>标签是后置增强的标签,属性基本和前置增强相同,唯一多了一个returning,这个属性会拿到目标方法的返回值,并作为参数传给后置增强的方法,属性值必须和增强方法的参数名一样。

3、如何基于Schema写一个环绕增强的例子?

  有了上面的经验,我们写出如下代码:
Lecturer.java(目标类)

package com.spring.test;

/**
 * 讲师类,具有上课方法
 * @author beijingduanluo
 *
 */
public class Lecturer {
    public void classBegin(){
        System.out.println("讲师传授新技术,同学们讨论很激烈!");
    }
}

LecturerAdvice.java(增强类)

package com.spring.test;

import org.aspectj.lang.ProceedingJoinPoint;

public class LecturerAdvice{
    /**
     * 后置增强的横切逻辑
     */
    public void afterAdvice(ProceedingJoinPoint pjp) {
        System.out.println("这是环绕增强执行目标方法前。");
        try {
            pjp.proceed();
        } catch (Throwable e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println("这是环绕增强执行目标方法后");
    }

}

ApplicationContext.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:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:context="http://www.springframework.org/schema/context"
    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-4.3.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">

    <!-- 配置目标类 -->
    <bean id="lecturer" class="com.spring.test.Lecturer"></bean>
    <!-- 配置增强类 -->
    <bean id="advice" class="com.spring.test.LecturerAdvice"></bean>

    <!-- 开始aop配置 -->
    <aop:config>
        <!-- 配置切点 -->
        <aop:pointcut expression="target(com.spring.test.Lecturer) and execution(public void classBegin())" id="pointcut"/>
        <aop:aspect ref="advice">
            <aop:around method="afterAdvice" pointcut-ref="pointcut"/>
        </aop:aspect>
    </aop:config>


</beans>

SpringTest.java(测试类)

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.spring.test.Lecturer;

public class SpringTest{

    public static void main(String[] args){
        ApplicationContext content = new ClassPathXmlApplicationContext("applicationcontext.xml");
        Lecturer lecturer = (Lecturer) content.getBean("lecturer");
        lecturer.classBegin();
    }
}

控制台

这是环绕增强执行目标方法前。
讲师传授新技术,同学们讨论很激烈!
这是环绕增强执行目标方法后

  配置文件的环绕增强标签用的是<aop:around>,里面的属性都说过了,但是在增强方法里出现了一个新的api—ProceedingJoinPoint,这个类型的对象调用proceed方法可以调用目标方法。

4、如何基于Schema写一个异常抛出增强的例子?

  有了上面的经验,我们写出如下代码:
Lecturer.java(目标类)

package com.spring.test;

/**
 * 讲师类,具有上课方法
 * @author beijingduanluo
 *
 */
public class Lecturer {
    public void classBegin() throws Exception{
        System.out.println("讲师传授新技术,同学们讨论很激烈!");
        throw new Exception("自己制造的一个错误");
    }
}

LecturerAdvice.java(增强类)

package com.spring.test;

import org.aspectj.lang.ProceedingJoinPoint;

public class LecturerAdvice{
    /**
     * 异常抛出增强的横切逻辑
     */
    public void throwsAdvice(Exception e) {
        System.out.println("异常抛出增强的异常信息是"+e.getMessage());
    }

}

ApplicationContext.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:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:context="http://www.springframework.org/schema/context"
    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-4.3.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">

    <!-- 配置目标类 -->
    <bean id="lecturer" class="com.spring.test.Lecturer"></bean>
    <!-- 配置增强类 -->
    <bean id="advice" class="com.spring.test.LecturerAdvice"></bean>

    <!-- 开始aop配置 -->
    <aop:config>
        <!-- 配置切点 -->
        <aop:pointcut expression="target(com.spring.test.Lecturer) and execution(public void classBegin())" id="pointcut"/>
        <aop:aspect ref="advice">
            <aop:after-throwing throwing="e" method="throwsAdvice" pointcut-ref="pointcut"/>
        </aop:aspect>
    </aop:config>
</beans>

SpringTest.java(测试类)

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.spring.test.Lecturer;

public class SpringTest{

    public static void main(String[] args){
        ApplicationContext content = new ClassPathXmlApplicationContext("applicationcontext.xml");
        Lecturer lecturer = (Lecturer) content.getBean("lecturer");
        try {
            lecturer.classBegin();
        } catch (Exception e) {
            // TODO Auto-generated catch block
        }
    }
}

控制台

讲师传授新技术,同学们讨论很激烈!
异常抛出增强的异常信息是自己制造的一个错误

  异常抛出增强使用的标签是<aop:after-throwing>,这个标签所有属性和前面几乎相同,唯一多了一个throwing属性,这个属性将目标方法的异常获取到并给到增强方法的参数,属性值和增强方法的参数名必须相同。
  如果throwing属性不写,那增强方法的参数也不可以存在。

5、如何基于Schema写一个引介增强的例子?

  引介增强和上面几个增强还是有些区别的,上面的增强切入点都是方法,引介增强的切入点是类,我们看一下引介增强的代码:
Lecturer.java(目标类)

package com.spring.test;

/**
 * 讲师类,具有上课方法
 * @author beijingduanluo
 *
 */
public class Lecturer {
    public void classBegin() throws Exception{
        System.out.println("讲师传授新技术,同学们讨论很激烈!");
        throw new Exception("自己制造的一个错误");
    }
}

School.java(目标接口)

package com.spring.test;

public interface School {
    public void setRest(boolean rest);
    public boolean getRest();
}

SchoolImpl.java(目标接口的默认实现类,也可以看成增强)

package com.spring.test;

public class SchoolImpl implements School {

    private boolean rest;
    public void setRest(boolean rest) {
        // TODO Auto-generated method stub
        this.rest = rest;
    }
    public boolean getRest() {
        // TODO Auto-generated method stub
        return rest;
    }

}

ApplicationContext.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:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:context="http://www.springframework.org/schema/context"
    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-4.3.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">

    <!-- 配置目标类 -->
    <bean id="lecturer" class="com.spring.test.Lecturer"></bean>

    <!-- 开始aop配置 -->
    <aop:config>
        <!-- 配置切点 -->
        <aop:pointcut expression="target(com.spring.test.Lecturer) and execution(public void classBegin())" id="pointcut"/>
        <aop:aspect ref="advice">
            <aop:declare-parents default-impl="com.spring.test.SchoolImpl" types-matching="com.spring.test.Lecturer" implement-interface="com.spring.test.School"/>
        </aop:aspect>
    </aop:config>


</beans>

SpringTest.java(测试类)

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.spring.test.Lecturer;
import com.spring.test.School;

public class SpringTest{

    public static void main(String[] args){
        ApplicationContext content = new ClassPathXmlApplicationContext("applicationcontext.xml");
        Lecturer lecturer = (Lecturer) content.getBean("lecturer");
        School restLec = (School) lecturer;
        restLec.setRest(true);
        System.out.println(restLec.getRest());
    }
}

  最后控制台打印true,证明Lecturer类已经实现了School接口。
  我们看一下引介增强的标签<aop:declare-parents>,属性types-matching的值是目标类的全限定名,属性implement-interface的值是目标接口的全限定名,属性default-impl的值是接口默认实现类的全限定名。
  到此为止,我们基于Schema的AOP已经讲完了。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值