欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Spring AOP(基于代理的实现)

程序员文章站 2022-07-12 14:29:32
...

1、介绍。

        Aspect(切面):在Aspect中会包含着一些Pointcut以及相应的Advice。
        Pointcut(切入点):定义了相应Advice要发生的地方。AOP提供多种触发方式,而Spring只有在方法被调用时触发。
        Advice(通知):Advice定义了在Pointcut(切点)具体要做的操作。
        Target(目标对象):织入Advice的目标对象。
        Weaving(织入):将Aspect和其他对象连接起来。
        
        before advice, 在Pointcut前被执行的advice。
        after return advice, 在一个Pointcut正常返回后执行的advice
        after throwing advice, 当一个Pointcut抛出异常后执行的advice
        after(final) advice, 无论一个Pointcut是正常退出还是发生了异常, 都会被执行的advice.
        around advice, 在Pointcut前和Pointcut退出后都执行的advice. 这个是最常用的advice.
        introduction,introduction可以为原有的对象增加新的属性和方法。

2、项目目录结构。

Spring AOP(基于代理的实现)

3、pom.xml。

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zxj</groupId>
    <artifactId>zxj-spring</artifactId>
    <version>1.0-SNAPSHOT</version>

    <name>zxj-spring</name>
    <!-- FIXME change it to the project's website -->
    <url>http://www.example.com</url>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.7</maven.compiler.source>
        <maven.compiler.target>1.7</maven.compiler.target>
        <spring.version>4.3.18.RELEASE</spring.version>
    </properties>

    <dependencies>
        <!--测试-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>${spring.version}</version>
            <scope>test</scope>
        </dependency>
        <!--Spring-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>

    </dependencies>

    <build>
        <finalName>${project.artifactId}</finalName>
        <plugins>
            <plugin>
                <artifactId>maven-clean-plugin</artifactId>
                <version>3.1.0</version>
            </plugin>
            <plugin>
                <artifactId>maven-install-plugin</artifactId>
                <version>2.5.2</version>
            </plugin>
        </plugins>
    </build>
</project>

4、主流程代码(在单元测试中)。

package com.zxj;

import com.zxj.dao.entity.User;
import com.zxj.dao.service.IUserService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

//junit测试单元要使用下面两个注解,否则@Autowwire为null
@RunWith(SpringJUnit4ClassRunner.class)//可能会报junit版本过低的错误,将其变高就可以了
@ContextConfiguration("classpath:spring.xml")
public class AopTest {
    @Autowired
    @Qualifier(value = "userServiceProxy")
    private IUserService userService;
    @Autowired
    @Qualifier(value = "childServiceProxy")
    private IUserService childService;

    @Test
    public void aopTest1() {
        System.out.println();

        User user=new User();
        user.setName("小明");
        user.setAge(12);
        userService.printInfo(user);

        System.out.println();

        User child=new User();
        child.setName("小红");
        child.setAge(18);
        childService.printInfo(child);

        System.out.println();
    }
}

5、Spring.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: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.xsd">

    <!--要扫描包-->
    <context:component-scan base-package="com.zxj"/>

    <!--Pointcut(切入点):定义了相应Advice要发生的地方。-->
    <bean id="userPointcut" class="org.springframework.aop.support.JdkRegexpMethodPointcut">
        <property name="pattern" value=".*printInfo"/>
    </bean>

    <!--Aspect(切面):在Aspect中会包含着一些Pointcut以及相应的Advice。-->
    <bean id="userAdvice" class="org.springframework.aop.support.DefaultPointcutAdvisor">
        <property name="advice" ref="userAdviceHandle"/>
        <property name="pointcut" ref="userPointcut"/>
    </bean>

    <!--Weaving(织入):将Aspect和其他对象连接起来。-->
    <bean id="userServiceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
        <property name="target" ref="userService"/><!--被代理类-->
        <property name="interceptorNames" value="userAdvice"/><!--Aspect(切面)-->
        <property name="proxyInterfaces" value="com.zxj.dao.service.IUserService"/><!--被代理类的实现接口-->
    </bean>
    <bean id="childServiceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
        <property name="target" ref="childService"/><!--被代理类-->
        <property name="interceptorNames" value="userAdvice"/><!--Aspect(切面)-->
        <property name="proxyInterfaces" value="com.zxj.dao.service.IUserService"/><!--被代理类的实现接口-->
    </bean>
</beans>

6、 Advice(通知):Advice定义了在Pointcut(切点)具体要做的操作。

package com.zxj.test.aop;

import com.zxj.dao.entity.User;
import org.springframework.aop.AfterReturningAdvice;
import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
 * Advice定义了在Pointcut(切点)具体要做的操作。
 * <p>
 * AOP中的Joinpoint可以有多种类型:构造方法调用,字段的设置和获取,方法的调用,方法的执行,
 * 异常的处理执行,类的初始化。但是Spring只支持方法执行类型的Joinpoint。
 * <p>
 * before advice, 在Pointcut前被执行的advice。
 * after return advice, 在一个Pointcut正常返回后执行的advice
 * after throwing advice, 当一个Pointcut抛出异常后执行的advice
 * after(final) advice, 无论一个Pointcut是正常退出还是发生了异常, 都会被执行的advice.
 * around advice, 在Pointcut前和Pointcut退出后都执行的advice. 这个是最常用的advice.
 * introduction,introduction可以为原有的对象增加新的属性和方法。
 */
@Component(value = "userAdviceHandle")
public class UserAdviceHandle implements MethodBeforeAdvice, AfterReturningAdvice {
    private final int adultAge = 16;

    @Override
    public void before(Method method, Object[] objects, Object target) throws Throwable {
        System.out.println(String.format("%s %s before", target.getClass().getName(), method.getName()));
        User user = (User) objects[0];
        if (user.getAge() > adultAge) {
            System.out.println(String.format("%s已成年", user.getName()));
        } else {
            System.out.println(String.format("%s未成年", user.getName()));
        }
    }

    @Override
    public void afterReturning(Object o, Method method, Object[] objects, Object target) throws Throwable {
        System.out.println(String.format("%s %s afterReturning", target.getClass().getName(), method.getName()));
        User user = (User) objects[0];
        int ageDiff = Math.abs(user.getAge() - adultAge);
        if (user.getAge() > adultAge) {
            System.out.println(String.format("%s%d年前就成年了", user.getName(), ageDiff));
        } else {
            System.out.println(String.format("%s还有%d年才成年", user.getName(), ageDiff));
        }
    }
}

7、User.java、IUserService.java、UserServiceImpl.java、ChildServiceImpl.java。

package com.zxj.dao.entity;

public class User {
    private String name;
    private int age;

    public User(){

    }

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}
package com.zxj.dao.service;

import com.zxj.dao.entity.User;

public interface IUserService {
    void printInfo(User user);
}
package com.zxj.dao.service.impl;

import com.zxj.dao.entity.User;
import com.zxj.dao.service.IUserService;
import org.springframework.stereotype.Service;

@Service(value = "userService")
public class UserServiceImpl implements IUserService {
    @Override
    public void printInfo(User user) {
        System.out.println(String.format("用户%s已经%d岁了", user.getName(), user.getAge()));
    }
}
package com.zxj.dao.service.impl;

import com.zxj.dao.entity.User;
import com.zxj.dao.service.IUserService;
import org.springframework.stereotype.Service;

@Service(value = "childService")
public class ChildServiceImpl implements IUserService {
    @Override
    public void printInfo(User user) {
        System.out.println(String.format("小孩:%s已经%d岁了", user.getName(), user.getAge()));
    }
}

8、结果。

Spring AOP(基于代理的实现)

相关标签: spring