ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Spring AOP 01_初始AOP 及两种动态代理方法

2022-05-15 20:33:37  阅读:130  来源: 互联网

标签:01 target Spring 代理 System AOP println public


一、Spring AOP简介

AOP的全称是Aspect-Oriented Programming,即面向切面编程(也称面向方面编程)。它是面向对象编程(OOP)的一种补充,目前已成为一种比较成熟的编程方式。

在传统的业务处理代码中,通常都会进行事务处理、日志记录等操作。虽然使用OOP可以通过组合或者继承的方式来达到代码的重用,但如果要实现某个功能(如日志记录),同样的代码仍然会分散到各个方法中。这样,如果想要关闭某个功能,或者对其进行修改,就必须要修改所有的相关方法。这不但增加了开发人员的工作量,而且提高了代码的出错率。

为了解决这一问题,AOP思想随之产生。AOP采取横向抽取机制,将分散在各个方法中的重复代码提取出来,然后在程序编译或运行时,再将这些提取出来的代码应用到需要执行的地方。这种采用横向抽取机制的方式,采用传统的OOP思想显然是无法办到的,因为OOP只能实现父子关系的纵向的重用。虽然AOP是一种新的编程思想,但却不是OOP的替代品,它只是OOP的延伸和补充。

类与切面的关系

image
AOP的使用,使开发人员在编写业务逻辑时可以专心于核心业务,而不用过多的关注于其他业务逻辑的实现,这不但提高了开发效率,而且增强了代码的可维护性。

AOP术语

image

Proxy(代理):将通知应用到目标对象之后,被动态创建的对象。
Weaving(织入):将切面代码插入到目标对象上,从而生成代理对象的过程。

二、动态代理

  1. JDK动态代理
    JDK动态代理是通过java.lang.reflect.Proxy 类来实现的,我们可以调用Proxy类的newProxyInstance()方法来创建代理对象。对于使用业务接口的类,Spring默认会使用JDK动态代理来实现AOP。

案例

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>org.example</groupId>
    <artifactId>Spring_AOP</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.26</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.9</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>5.0.5.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>5.0.5.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.0.5.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.0.5.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>5.0.5.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.0.5.RELEASE</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>2.0.7</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.10.3</version>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter</artifactId>
            <version>RELEASE</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>
</project>

一、静态代理

1. 构造函数方法给代理对象赋值
接口类UserDao
public interface UserDao {
    public void addUser();
    public void deleteUser();
}
实现类UserDaoImpl
import sse.dao.UserDao;

public class UserDaoImpl implements UserDao {
    @Override
    public void addUser() {
        System.out.println("add user!");
    }

    @Override
    public void deleteUser() {
        System.out.println("delete user!");
    }
}
代理类UserDaoProxy
import sse.dao.UserDao;
import sse.dao.impl.UserDaoImpl;

//模拟日志
public class UserDaoProxy implements UserDao {

    private  UserDao target;

    public UserDaoProxy(UserDao target) {  //构造函数方法给代理对象赋值
        this.target = target;
    }

    @Override
    public void addUser() {
        System.out.println("开始添加用户");
        target.addUser();
        System.out.println("完成添加用户");
    }

    @Override
    public void deleteUser() {
        System.out.println("开始删除用户");
        target.deleteUser();
        System.out.println("完成删除用户");
    }
}
测试

image

2. set方法
接口类BookDao
public interface BookDao {
    void addBook();
}
实现接口的类BookDaoImpl
import sse.dao.BookDao;

public class BookDaoImpl implements BookDao {
    @Override
    public void addBook() {
        System.out.println("添加书籍");
    }
}
静态代理BookDaoProxy
import sse.dao.BookDao;

public class BookDaoProxy implements BookDao {

    private BookDao target;

    public void setTarget(BookDao target) { //set方法给代理对象赋值
        this.target = target;
    }

    @Override
    public void addBook() {
        System.out.println("开始添加书籍");
        target.addBook();
        System.out.println("完成添加书籍");
    }
}
测试

image

二、jdk动态代理

动态代理类JdkProxy
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
//通用代理类
public class JdkProxy implements InvocationHandler {
    private  Object target;//通用代理类,既可以代理UserDao,也可以代理BookDao

    public JdkProxy(Object target) {
        this.target = target;
    }

    /*
*   invoke方法在反射机制中用到,它可以根据方法名动态地调用不同的方法,有可能调用addUser(),也有可能调用addBook(),我们把它们组合到invoke()方法里面
*    在invoke方法里我们通过参数调用实际的方法(具体的方法是通过参数传进来的)
*    通过method.invoke()传进来的有可能是addUser(),也可能是addBook(),方法里面有两个参数,一个是调用的target,一个是其参数
* * */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        System.out.println(method.getName()+"被调用前");
        Object ret = method.invoke(target,args);
        System.out.println(method.getName()+"被调用后");

        return ret;

    }
}
  • 测试1

image

  • 测试2

image

标签:01,target,Spring,代理,System,AOP,println,public
来源: https://www.cnblogs.com/oyww-2027/p/16271606.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有