Spring教程18-使用XML配置切面

阅读原文
之前关于切面的创建我们都是基于Java配置讲解的,这篇我们将以XML配置的方式来对之前的讲解做一次回顾,以下的代码我就不做讲解了,只是换了一种配置方式,实现原理之前都讨论过了,我们直接看代码。

一、创建一个简单的切面

1、创建UserService接口以及实现类

public interface UserService {
    public boolean saveUser(Long id, String userName);
}
public class UserServiceImpl implements UserService {
    @Override
    public boolean saveUser(Long id, String userName) {
        return false;
    }
}

2、创建一个简单的切面类

public class SimpleAspect {
    public static Logger logger = LoggerFactory.getLogger(SimpleAspect.class);
    /**
     * 前置通知方法
     */
    public void before() {
        logger.info("*************执行方法前调用*************");
    }
    /**
     * 后置通知方法
     */
    public void after() {
        logger.info("*************执行方法后或者抛出异常后调用*************");
    }
    /**
     * 异常通知方法
     */
    public void throwable() {
        logger.info("*************执行方法异常后调用*************");
    }
    /**
     * 返回通知方法
     */
    public void returning() {
        logger.info("*************执行方法后后调用, 异常不会调用*************");
    }
}

3、基于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: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/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd">
    <!-- ****************简单切面配置********************** -->
    <!-- 启用动态代理 -->
    <aop:aspectj-autoproxy/>
    <!-- 配置userServiceBean -->
    <bean id="userService" class="com.icypt.learn.service.impl.UserServiceImpl"/>
    <bean id="simpleAspect" class="com.icypt.learn.aspect.SimpleAspect"/>
    <!-- aop配置-->
    <aop:config>
        <aop:aspect ref="simpleAspect">
            <!--定义切点-->
            <aop:pointcut id="process" expression="execution(* com.icypt.learn.service.UserService.saveUser(..))"/>
            <!--前置通知-->
            <aop:before method="before" pointcut-ref="process"/>
            <!--后置通知-->
            <aop:after method="after" pointcut-ref="process"/>
            <!--异常通知-->
            <aop:after-throwing method="throwable" pointcut-ref="process"/>
            <!--返回通知-->
            <aop:after-returning method="returning" pointcut-ref="process"/>
        </aop:aspect>
    </aop:config>
</beans>

4、编写测试类

public class TestUserService {
    public static Logger logger = LoggerFactory.getLogger(TestUserService.class);
    public static ClassPathXmlApplicationContext cpxac = new ClassPathXmlApplicationContext("simpleAspect.xml");
    @Test
    public void testSaveUser() {
        UserService userService = cpxac.getBean("userService", UserService.class);
        //调用目标方法
        boolean flag = userService.saveUser(1l,"daguo");
        logger.info("***********执行目标类saveUser方法结果:" + flag + "**********");
    }
}

5、运行测试类

21:32:20,689  INFO main aspect.SimpleAspect:21 - *************执行方法前调用*************
21:32:20,689  INFO main aspect.SimpleAspect:28 - *************执行方法后或者抛出异常后调用*************
21:32:20,689  INFO main aspect.SimpleAspect:42 - *************执行方法后后调用, 异常不会调用*************
21:32:20,689  INFO main service.TestUserService:25 - ***********执行目标类saveUser方法结果:false**********

6、结果分析

通过运行结果可以发现我们配置简单切面已经正常运行了,下面就个配置节点予以说明:
:声明一个Bean组件,功能与@Bean或者@Component注解相同。
<aop:aspectj-autoproxy/>:表示开启自动代理,功能与@EnableAspectJAutoProxy注解相同。
<aop:aspect/>:表示配置一个切面,功能与@Aspect注解相同。
<aop:pointcut/>:表示配置一个切点,功能与@Pointcut注解相同。
<aop:before/>:表示配置前置通知,功能与@Before注解相同。
<aop:after/>:表示配置后置通知,功能与@After注解相同。
<aop:after-throwing/>:表示配置异常通知,功能与@AfterThrowing注解相同。
<aop:after-returning/>:表示配置返回通知,功能与@AfterReturning注解相同。

二、创建一个环绕通知的切面

1、创建一个环绕通知的切面类

public class AroundAspect {
    public static Logger logger = LoggerFactory.getLogger(AroundAspect.class);
    public Object around(ProceedingJoinPoint pjp) {
        Object object = null;
        logger.info("*************执行方法前调用*************");
        try {
            object =  pjp.proceed();
            logger.info("*************执行方法后后调用, 异常不会调用*************");
        } catch (Throwable throwable) {
            logger.error("*************执行方法异常后调用*************", throwable);
        } finally {
            logger.info("*************执行方法后或者抛出异常后调用*************");
        }
        return object;
    }
}

2、基于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: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/aop 
	   http://www.springframework.org/schema/aop/spring-aop.xsd">
    <!-- *******************切面环绕通知配置 -->
    <!-- 启用动态代理 -->
    <aop:aspectj-autoproxy/>
    <!-- 配置Bean -->
    <bean id="userService" class="com.icypt.learn.service.impl.UserServiceImpl"/>
    <bean id="aroundAspect" class="com.icypt.learn.aspect.AroundAspect"/>

    <!-- aop配置-->
    <aop:config>
        <aop:aspect ref="aroundAspect">
            <!--定义切点-->
            <aop:pointcut id="process" expression="execution(* com.icypt.learn.service.UserService.saveUser(..))"/>
            <!--前置通知-->
            <aop:around method="around" pointcut-ref="process"/>
        </aop:aspect>
    </aop:config>
</beans>

3、修改测试类

public static ClassPathXmlApplicationContext cpxac = new ClassPathXmlApplicationContext("aroundAspect.xml");

4、运行测试类

22:15:57,270  INFO main aspect.AroundAspect:20 - *************执行方法前调用*************
22:15:57,270  INFO main aspect.AroundAspect:23 - *************执行方法后后调用, 异常不会调用*************
22:15:57,270  INFO main aspect.AroundAspect:27 - *************执行方法后或者抛出异常后调用*************
22:15:57,270  INFO main service.TestUserService:25 - ***********执行目标类saveUser方法结果:false**********

5、结果分析

由运行结果可知我们配置的环绕通知的切面已正常共工作,其中<aop:around/>表示配置的是一个环绕通知,与@Around注解功能相同。

三、创建一个接受参数的切面

1、创建一个接受参数的切面类

public class GetParamsAspect {
    public static Logger LOGGER = LoggerFactory.getLogger(GetParamsAspect.class);
    public void before(Long userId, String userName) {
        LOGGER.info("***********************进入前置通知**********************************");
        LOGGER.info("前置通知接受的userId:" + userId);
        LOGGER.info("前置通知接受的userName:" + userName);
    }
}

2、基于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: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/aop 
	   http://www.springframework.org/schema/aop/spring-aop.xsd">
    <!-- *****************切面获取参数配置********************* -->
    <!-- 启用动态代理 -->
    <aop:aspectj-autoproxy/>
    <!-- 配置Bean -->
    <bean id="userService" class="com.icypt.learn.service.impl.UserServiceImpl"/>
    <bean id="getParamsAspect" class="com.icypt.learn.aspect.GetParamsAspect"/>

    <!-- aop配置-->
    <aop:config>
        <aop:aspect ref="getParamsAspect">
            <!--定义切点-->
            <aop:pointcut id="process" expression="execution(* com.icypt.learn.service.UserService.saveUser(Long,String)) and args(userId, userName)"/>
            <!--前置通知-->
            <aop:before method="before" pointcut-ref="process"/>
        </aop:aspect>
    </aop:config>
</beans>

3、修改测试类

 public static ClassPathXmlApplicationContext cpxac = new ClassPathXmlApplicationContext("getParamsAspect.xml");

4、运行测试类

22:22:54,766  INFO main aspect.GetParamsAspect:12 - ***********************进入前置通知**********************************
22:22:54,782  INFO main aspect.GetParamsAspect:13 - 前置通知接受的userId:1
22:22:54,782  INFO main aspect.GetParamsAspect:14 - 前置通知接受的userName:daguo
22:22:54,782  INFO main service.TestUserService:25 - ***********执行目标类saveUser方法结果:false**********

5、结果分析

通过运行结果可知我们已经能够成功获取目标方法执行时携带的参数,需要注意的是args()切点指示器指定的参数名称必须和目标方法的参数名称保持一致。

四、创建一个引入功能的切面

1、增加引入功能的接口以及实现类

public interface EnhanceUserService {
    public boolean update();
}
public class EnhanceUserServiceImpl implements EnhanceUserService  {
    public static Logger logger = LoggerFactory.getLogger(EnhanceUserServiceImpl.class);
    @Override
    public boolean update() {
        logger.info("************执行增强后新增的update方法****************");
        return false;
    }
}

2、基于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: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/aop 
	   http://www.springframework.org/schema/aop/spring-aop.xsd">
    <!-- *******************切面引入功能配置********************** -->
    <!-- 启用动态代理 -->
    <aop:aspectj-autoproxy/>
    <!-- 配置Bean -->
    <bean id="userService" class="com.icypt.learn.service.impl.UserServiceImpl"/>
    <bean id="aroundAspect" class="com.icypt.learn.aspect.AroundAspect"/>

    <!-- aop配置-->
    <aop:config>
        <aop:aspect>
            <aop:declare-parents types-matching="com.icypt.learn.service.UserService+" 
			<!--扩展功能的接口-->
			implement-interface="com.icypt.learn.service.EnhanceUserService"
			<!--扩展功能的默认实现-->
            default-impl="com.icypt.learn.service.impl.EnhanceUserServiceImpl"/>
        </aop:aspect>
    </aop:config>
</beans>

3、创建测试类

public class TestEnhanceUserService {
    public static Logger logger = LoggerFactory.getLogger(TestEnhanceUserService.class);
    public static ClassPathXmlApplicationContext cpxac = new ClassPathXmlApplicationContext("enhanceAspect.xml");
    @Test
    public void testSaveUser() {
        UserService userService = cpxac.getBean("userService", UserService.class);
        //调用目标方法
        boolean flag = userService.saveUser(1l,"daguo");
        logger.info("***********执行目标类saveUser方法结果:" + flag + "**********");
        //调用目标类引入方法
        EnhanceUserService enhanceUserService = (EnhanceUserService) userService;
        enhanceUserService.update();
    }
}

4、运行测试类

22:34:50,859  INFO main service.TestEnhanceUserService:24 - ***********执行目标类saveUser方法结果:false**********
22:34:50,859  INFO main impl.EnhanceUserServiceImpl:14 - ************执行增强后新增的update方法****************

5、结果分析

由运行结果可以看到,我们通过扩展接口新增的方法已经成功执行,可见切面引入功能正常。
<aop:declare-parents/>:表示将创建一个代理类同时代理目标类和功能扩展类,这样调用端就可以同时调用目标类和功能扩展类的方法了。到此,我们关于Spring的核心依赖注入和切面编程已全部讲解完毕,接下来我们将进入SpringWeb的学习。
关于之前的讲解大家有什么疑问或者觉得我的理解有偏差,可以在公众号或者qq留言,我会及时更正。

更多最新技术文章,请关注“冰点IT”公众号

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值