天天看点

13-实现springAop的3种方式

文章目录

    • aop实现方式1(实现spring接口)
      • 导包
      • 业务模块service
      • 代理模块
      • 测试
    • Aop实现方式2(自定义切入类)
    • aop实现方式3(使用注解开发)

项目地址

aop实现方式1(实现spring接口)

导包

使用之前要导入依赖包

13-实现springAop的3种方式
<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.2.9.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
    </dependency>
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.9.6</version>
    </dependency>
</dependencies>
           

项目结构:

spring1-aop
├───.idea
├───src
│   ├───main
│   │   ├───java
│   │   │   └───com
│   │   │       └───ajream
│   │   │           ├───log
│   │   │           └───service
│   │   └───resources
│   └───test
        └───java
           

业务模块service

被代理的接口,包含了要实现的具体功能

UserService.java接口:

package com.ajream.service;

public interface UserService {
    void add();
    void delete();
    void update();
    void query();
}
           

UserServiceImpl.java

package com.ajream.service;

public class UserServiceImpl implements UserService {
    @Override
    public void add() {
        System.out.println("增加一个用户");
    }

    @Override
    public void delete() {
        System.out.println("删除一个用户");
    }

    @Override
    public void update() {
        System.out.println("修改一个用户");
    }

    @Override
    public void query() {
        System.out.println("查询一个用户");
    }
}

           

代理模块

在原有基础上扩展一些功能

Log.java (在实现某个业务(调用某个方法)前,打印一些相关信息)

说明:重写MethodBeforeAdvice接口的before方法,说明在切入点之前执行这个方法
package com.ajream.log;

import org.springframework.aop.MethodBeforeAdvice;

import java.lang.reflect.Method;

public class Log implements MethodBeforeAdvice {
    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {
        assert target != null;
        System.out.println(target.getClass().getName() + "的" + method.getName() + "方法被执行了");
    }
}

           

AfterLog.java (在实现某个业务(调用某个方法)后,打印一些相关信息)

说明:重写AfterReturningAdvice的

afterReturning

方法,说明在切入点之后执行这个方法
package com.ajream.log;

import org.springframework.aop.AfterReturningAdvice;
import java.lang.reflect.Method;

public class AfterLog implements AfterReturningAdvice {
    @Override
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
        System.out.println("执行了" +method.getName()+ "方法,返回值为:"+returnValue);
    }
}

           

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:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd"
>

    <bean id="userService" class="com.ajream.service.UserServiceImpl" />
    <bean id="log" class="com.ajream.log.Log" />
    <bean id="afterLog" class="com.ajream.log.AfterLog" />

    <aop:config>
<!--    定义切入点pointcut, execution(返回类型 包名.类名.方法名(参数))  "*"表示任意 -->
        <aop:pointcut id="pointCut" expression="execution(* com.ajream.service.UserServiceImpl.*(..))"/>

<!--    执行环绕增加-->
        <aop:advisor advice-ref="afterLog" pointcut-ref="pointCut" />
        <aop:advisor advice-ref="log" pointcut-ref="pointCut"/>

    </aop:config>

</beans>
           
说明:
  1. 注意添加aop支持
    xmlns:aop="http://www.springframework.org/schema/aop"
    http://www.springframework.org/schema/aop
    https://www.springframework.org/schema/aop/spring-aop.xsd
               
  2. aop配置(使用原生spring api接口)
    <aop:config>    
        <!--定义切入点pointcut, execution(返回类型 包名.类名.方法名(参数))  "*"表示任意 -->   
    	<aop:pointcut id="pointCut" expression="execution(* com.ajream.service.UserServiceImpl.*(..))"/>    
    	<!--执行环绕增加,即在切入点前后执行下面的操作-->    
    	<aop:advisor advice-ref="afterLog" pointcut-ref="pointCut" />    
    	<aop:advisor advice-ref="log" pointcut-ref="pointCut"/>
    </aop:config>
               

测试

MyTest.java测试

import com.ajream.service.UserService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
	@Test
	public void test(){
	    ApplicationContext context  =  new ClassPathXmlApplicationContext("ApplicationContext.xml");
	    //动态代理的是接口        
	    UserService userService = context.getBean("userService", UserService.class);        userService.add();    
	}
}
           

测试结果:

13-实现springAop的3种方式

Aop实现方式2(自定义切入类)

主要是aop配置方式不同

之前是使用原生spring api方式,分别实现了

MethodBeforeAdvice

AfterReturningAdvice

这两个接口,因此在xml中只需要指明要切入哪个位置,执行什么操作,在执行目标接口的方法时spring就会根据xml配置自动去执行对应操作,如下:

<aop:config>    
	<!--定义切入点pointcut, execution(返回类型 包名.类名.方法名(参数))  "*"表示任意 -->    
	<aop:pointcut id="pointCut" expression="execution(* com.ajream.service.UserServiceImpl.*(..))"/>        
	<!--执行环绕增加,即在切入点前后执行下面的操作-->    
	<aop:advisor advice-ref="afterLog" pointcut-ref="pointCut" />    
	<aop:advisor advice-ref="log" pointcut-ref="pointCut"/>    
</aop:config>
           

现在改用自定义切入面方式:

首先添加一个切面DiyPointCut(即一个类,包含了要切入的方法)

package com.ajream.diy;

//自定义切入面
public class DiyPointCut {
    public void before(){
        System.out.println("=====方法执行前======");
    }    
    public void after(){
        System.out.println("======方法执行后======");    
    }
}
           

aop配置:

<!--方式2:自定义类-->
<bean id="diy" class="com.ajream.diy.DiyPointCut" />
<aop:config>    
	<!--定义切面,ref为要引用的类-->    
	<aop:aspect ref="diy" >        
		<!--切入点-->        
		<aop:pointcut id="point" expression="execution(* com.ajream.service.UserServiceImpl.*(..))"/>   
		     
		<!-- aop:before表示在切入点point之前执行切面的before方法-->        
		<aop:before method="before" pointcut-ref="point"/>        
		<aop:after method="after" pointcut-ref="point" />    
	</aop:aspect>
</aop:config>
           

aop实现方式3(使用注解开发)

项目地址

首先开启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:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd"
>

    <bean id="userService" class="com.ajream.service.UserServiceImpl" />

<!--方式3,注解方式-->
    <bean id="annotationPointCut" class="com.ajream.diy.AnnotationPointCut" />
<!--开启aop注解支持-->
    <aop:aspectj-autoproxy />
</beans>
           

添加切面AnnotationPointCut.java类

package com.ajream.diy;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

@Aspect  //标注这是一个切面
public class AnnotationPointCut {

    @Before("execution(* com.ajream.service.UserServiceImpl.*(..))")        //切入位置
    public void before(){
        System.out.println("=====方法执行前=====");
    }

    @After("execution(* com.ajream.service.UserServiceImpl.*(..))")
    public void after(){
        System.out.println("=====方法执行后=====");
    }

    @Around("execution(* com.ajream.service.UserServiceImpl.*(..))")   //环绕增强
    public void around(ProceedingJoinPoint jp) throws Throwable {
        System.out.println("环绕前");
        Object proceed = jp.proceed();//        执行方法
        System.out.println("执行的方法签名:" + jp.getSignature());
        System.out.println("环绕后");

    }
}

           
注意,如果添加了环绕增强,首先执行环绕增强,执行了proceed方法后才会触发

@Before

@After

这2个注解的内容,所以输出结果如下:
13-实现springAop的3种方式