spring IoC (IDEA)—— 基于XML配置的Spring AOP

XML方式是我们在实际项目中使用比较多的,在我们没有切面类类的源代码时或者使用第三方的切面类时,就不能使用注解的方式,而且使用注解方式时,一旦程序编译后就不可以修改了。如果使用XML方式就不一样了,我们只需要修改XML文件就可以。

1.在pom.xml中引入依赖

  <dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjrt</artifactId>
    <version>1.8.6</version>
  </dependency>
  <dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.8.5</version>
  </dependency>
</dependencies>

2.在applicationContext.xml中引入AOP命名空间

<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 ">

3.目标类有实现接口

(1)定义业务接口

使用前面定义的接口!

package com.etc.service;

public interface UserService {
 
        //新增用户,为了简化不体现参数
        void addUser();
 
        //修改用户,为了简化不体现参数
        void editUser();
}

(2)定义目标实现类

package com.etc.service.impl;

import com.etc.service.UserService;

public class UserServiceImpl implements UserService {

    @Override
    public void addUser() {
        System.out.println("增加一个用户...");
    }

    @Override
    public void editUser() {
        System.out.println("修改用户信息...");
    }
}

(3)定义切面类

package com.etc.service.impl;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature;

import java.lang.reflect.Method;

//定义切面类
public class MyAspects {
    //前置通知
    public void beforeAdvice(JoinPoint jp) throws Exception{
        String classType = jp.getTarget().getClass().getName();
        Class<?> clazz = Class.forName(classType);
        String clazzName = clazz.getName();
        System.out.println(clazzName);

        MethodSignature signature = (MethodSignature) jp.getSignature();
        Method method = signature.getMethod();
        System.out.println("执行前置通知方法,当前方法名为:" + method.getName());
    }

    //后置通知
    public void afterAdvice(){
        System.out.println("执行后置通知方法");
    }

    //环绕通知
    public Object aroundAdvice(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("环绕通知执行前");
        Object result = pjp.proceed();
        System.out.println("环绕通知执行后");
        return result;
    }
}

(4)目标类和切面配置

配置顺序

在Spring配置文件中,所有AOP相关定义必须放在<aop:config>标签下,该标签下可以有<aop:pointcut>、<aop:advisor>、<aop:aspect>标签,配置顺序不可变。

扫描二维码关注公众号,回复: 3081027 查看本文章

§<aop:pointcut>:用来定义切入点,该切入点可以重用;

§<aop:advisor>:用来定义只有一个通知和一个切入点的切面;

§<aop:aspect>:用来定义切面,该切面可以包含多个切入点和通知,而且标签内部的通知和切入点定义是无序的;和advisor的区别就在此,advisor只包含一个通知和一个切入点。

Point的expression语法

语法:execution(修饰符 返回值 包名.类名/接口名.方法名(参数列表))

其中:

A.返回类型、方法名、参数是必须有的。

B.* 表示任意值. 比如返回类型,方法名等。

C.(..)可以代表所有参数,(*)代表一个参数,(*,String)代表第一个参数为任何值,第二个参数为String类型。

举例说明:

A.任意公共方法的执行:

execution(public * *(..))

B.任何一个以“set”开始的方法的执行:

execution(* set*(..))

C.com.etc.service.UserService 接口的任意方法的执行:

execution(* com.etc.service.UserService.*(..))

D.定义在com.etc.service包里的任意方法的执行:

execution(* com.etc.service.*.*(..))

E.定义在com.etc.service包和所有子包里的任意类的任意方法的执行:

execution(* com.etc.service..*.*(..))

F.定义在com.etc.service包和所有子包里的Test类的任意方法的执行:

execution(* com.etc.service..Test.*(..))")

注意:最靠近(..)的为方法名,靠近.*(..))的为类名或者接口名

applicationContext.xml中bean和aop配置(针对前置通知和后置通知)

    <!--目标对象-->
    <bean id="userServiceImpl" class="com.etc.service.impl.UserServiceImpl"></bean>

    <bean id="myAspects" class="com.etc.service.impl.MyAspects"></bean>
    <aop:config>
        <aop:pointcut id="pc1" expression="execution(* com.etc.service..*.*(..))"/>
        <aop:aspect ref="myAspects">
            <!--method指定切面类中的方法,pointcut-ref可以引用已定义的切点-->
            <aop:before method="beforeAdvice" pointcut-ref="pc1" />
            <!--也可以在pointcut属性中直接定义切点-->
            <aop:after method="afterAdvice" pointcut="execution(* com.etc.service..*.*(..))"/>
            <!--环绕通知-->
            <aop:around method="aroundAdvice" pointcut-ref="pc1" />
        </aop:aspect>
    </aop:config>

(5)测试

package com.etc.test;

import com.etc.service.UserService;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestAop {
    private ApplicationContext context;
    @Before
    public void init(){
        context = new ClassPathXmlApplicationContext("applicationContext.xml");
    }

    @Test
    public void testAdvice(){
        UserService service = context.getBean("userServiceImpl",UserService.class);
        service.addUser();
        service.editUser();
    }
}

测试结果

九月 08, 2018 2:16:42 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [applicationContext.xml]
初始化
com.etc.service.impl.UserServiceImpl
执行前置通知方法,当前方法名为:addUser
环绕通知执行前
增加一个用户...
环绕通知执行后
执行后置通知方法
com.etc.service.impl.UserServiceImpl
执行前置通知方法,当前方法名为:editUser
环绕通知执行前
修改用户信息...
环绕通知执行后
执行后置通知方法

 4.目标类没有实现接口

(1)定义目标实现类

package com.etc.service.impl;

public class UserServiceImpl2 {

        public void addUser() {
        System.out.println("增加一个用户...!");
        }

        public void editUser() {
        System.out.println("修改用户信息...!");
        }
}

(2)定义切面类

使用前面定义的切面类

(3)目标类和切面配置

    <bean id="userServiceImpl2" class="com.etc.service.impl.UserServiceImpl2"></bean>

使用前面定义的切面配置

(4)测试

package com.etc.test;

import com.etc.service.impl.UserServiceImpl2;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestAop4Cglib {
    private ApplicationContext context;
    @Before
    public void init(){
        context = new ClassPathXmlApplicationContext("applicationContext.xml");
    }

    @Test
    public void testAdvice(){
        UserServiceImpl2 userServiceImpl2 = (UserServiceImpl2)context.getBean("userServiceImpl2");
        System.out.println("类名:" + userServiceImpl2.getClass().getName());
        userServiceImpl2.addUser();
        userServiceImpl2.editUser();
    }
}

测试结果

信息: Loading XML bean definitions from class path resource [applicationContext.xml]
初始化
类名:com.etc.service.impl.UserServiceImpl2$$EnhancerBySpringCGLIB$$ebf405eb
com.etc.service.impl.UserServiceImpl2
执行前置通知方法,当前方法名为:addUser
环绕通知执行前
增加一个用户...!
环绕通知执行后
执行后置通知方法
com.etc.service.impl.UserServiceImpl2
执行前置通知方法,当前方法名为:editUser
环绕通知执行前
修改用户信息...!
环绕通知执行后
执行后置通知方法

猜你喜欢

转载自blog.csdn.net/Milan__Kundera/article/details/82529089
今日推荐