Spring基础——AOP面向切面编程

基础配置:

pom.xml导入依赖:

复制代码
    <dependencies>
<!--        核心容器(core container)-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>5.3.10</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>5.3.10</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.3.10</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>5.3.10</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-expression</artifactId>
            <version>5.3.10</version>
        </dependency>
<!--        AOP、aspects、spring-instrument 、messaging-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>5.3.10</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>1.9.7</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.7</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>5.3.10</version>
        </dependency>
<!--        Data Access/Intergration-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.3.10</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>5.3.10</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-orm</artifactId>
            <version>5.3.10</version>
        </dependency>
<!--        web-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>5.3.10</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.3.10</version>
        </dependency>
        <!-- 日志相关jar包 (可选)-->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>compile</scope>
        </dependency>

    <!--        jdbcTemplate-->
        <dependency>
            <groupId>commons-dbcp</groupId>
            <artifactId>commons-dbcp</artifactId>
            <version>1.4</version>
        </dependency>
        <dependency>
            <groupId>commons-pool</groupId>
            <artifactId>commons-pool</artifactId>
            <version>1.6</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>
    </dependencies>
dependencies
复制代码

补充属性注入依赖:

复制代码
<?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 https://www.springframework.org/schema/context/spring-context.xsd">

    <!--    ********IOC********-->

    <!--    id:对象名称,唯一标识
        class:该对象具体属于哪个类,要用全类名
        scope:范围。singleton单例,默认。prototype多例。request、session
        init-method:可以自己设置初始化方法
        destroy-method:可以自己设置销毁方法
-->
    <!--    XML方式测试1:简单尝试用spring-->
    <!--    <bean id="userDao" class="com.swpu.dao.UserDaoImpl" scope="singleton"-->
    <!--        init-method="initUserDaoImpl" destroy-method="destroyUserDaoImpl"></bean>-->

    <!--    context:component-scan base-package:扫描注解所在的包-->
    <!--    注解方式测试1:简单尝试用spring-->
    <!--    <context:component-scan base-package="com.swpu"></context:component-scan>-->
    
    <!--    注解方式:构造注解方式同属性注解方式同-->
    <context:component-scan base-package="com.swpu"></context:component-scan>

</beans>
Resources目录下添加beans.xml
复制代码

容器获取和AOP注解扫描:

(最后两句注释掉,因为测试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:context="http://www.springframework.org/schema/context"
       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/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">


    <context:component-scan base-package="com.swpu"/>

    <!--    **********测试AOP  XML方式***************-->
    <!--            切入点简写方式(根据个人情况简写):* *..*.*Service.get*(..)
                        public void com.swpu.service.BookService.getAllBooks()
                        public:不写
                        void:* 即无论任何返回值类型都可以
                        com.swpu.service包:包名一般都是只有最后一个包不同,*..*\
                        BookService类:*Service 表示任何名称以Service结尾的类都可以
                        getAllBooks():get*(..) 表示指定类下的名称为get开头的所有方法都可以。参数为任意参数
       -->
    <!--    ①自定义切面类对象-->
<!--    <bean id="transationAspect" class="com.swpu.aspectJ.TransationAspect"/>-->
<!--    <aop:config>-->
        <!--        ②将自定义切面类对象引入AOP的设置中-->
<!--        <aop:aspect ref="transationAspect">-->
        <!--            ③使用自定义切面AOP(通知+切入点)通知:如何使用切面。切入点:在哪里使用切面-->
            <!--前置通知-->
<!--            <aop:before method="startTrans" pointcut="execution(public void com.swpu.service.BookService.getAllBooks())"></aop:before>-->
            <!--后置通知-->
<!--            <aop:after-returning method="commitTrans" pointcut="execution(* *..*.*Service.get*(..))"></aop:after-returning>-->

<!--            测试其他通知-->
            <!-- 最终通知:报错也执行 -->
<!--            <aop:after method="commitTrans" pointcut="execution(* *..*.*Service.get*(..))"></aop:after>-->
            <!-- 异常通知:报错才执行 -->
<!--            <aop:after-throwing method="commitTrans" pointcut="execution(* *..*.*Service.get*(..))"></aop:after-throwing>-->
            <!-- 环绕通知:之前+之后  在transationAspect类自定义环绕方法around-->
<!--            <aop:around method="around" pointcut="execution(* *..*.*Service.get*(..))"></aop:around>-->
<!--        </aop:aspect>-->
<!--    </aop:config>-->


    <!--    **********测试AOP  注解方式***************-->
    <bean id="transationAspect" class="com.swpu.aspect.TransationAspect"></bean>
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
Resources目录下添加appcontext.xml
复制代码

 

测试AOP:

  1.写好整个结构,保证代码逻辑正常

  2.再写切面,测试切面

先简单定义Dao和DaoImpl:

public interface BookDao {
    void findAllBooks();
}
package com.swpu.dao;
复制代码
@Repository
public class BookDaoImpl implements BookDao {
    public void findAllBooks() {
        System.out.println("已查找到所有书籍");
    }
}
package com.swpu.dao;
复制代码

Service和ServiceImpl:

复制代码
public interface BookService {
    //在该方法的前后加上切面里的方法,开启事务和提交事务
    //思路:将自定义TransationAspect切面类的两个方法穿插进getAllBooks的前后

    //开启事务方法:自定义TransationAspect切面类的startTrans
    public void getAllBooks();
    //提交事务方法:自定义TransationAspect切面类的commitTrans


    //    测试其他通知,会报错的方法
    public void mistake();
}
package com.swpu.service;
复制代码
复制代码
@Service
public class BookServiceImpl implements BookService{

    @Autowired
    private BookDao bookDao;

    public void setBookDao(BookDao bookDao) {
        this.bookDao = bookDao;
    }

    public void getAllBooks() {
        bookDao.findAllBooks();
//        mistake();//报错
    }

    //报错方法
    public void mistake() {
        System.out.println(1/0);
        System.out.println("报错");
    }

}
package com.swpu.service;
复制代码

Test类:

复制代码
public class BookTest {

    @Test
    public void testAOP(){
        ApplicationContext ac = new ClassPathXmlApplicationContext("appContext.xml");
        BookController bookController = (BookController)ac.getBean("bookController");
        bookController.queryAllBooks();
    }

}
package com.swpu.test;
复制代码

如上为基本代码逻辑。

 

  写控制/界面层+切面层(注解形式):

复制代码
//前置通知
@Before(value = "execution(public void com.swpu.service.BookService.getAllBooks())")

//后置通知
@After(value = "execution(* *..*.*Service.get*(..))")
注解格式参考
复制代码
复制代码
@Controller
public class BookController {

    @Autowired
    private BookService bookService;

    public void setBookService(BookService bookService) {
        this.bookService = bookService;
    }

    public void queryAllBooks(){
        bookService.getAllBooks();
    }
}
package com.swpu.controller;
复制代码
复制代码
/**
 * 自定义切面类:事务切面
 * 注解形式:
 *
 * @Aspect:定义切面类
 * @Before前置通知
 * @AfterReturning后置通知
 * @Around环绕通知
 * @AfterThrowing异常通知
 * @After最终通知
 */
@Aspect
public class TransationAspect {

    //前置通知
    @Before(value = "execution(* *..*.*Service.get*(..))")
    public void startTrans() {
        System.out.println("开启事务");
    }

    //    @AfterReturning(value = "execution(* *..*.*Service.get*(..))")
    //    @AfterThrowing(value = "execution(* *..*.*Service.get*(..))")
    //后置通知
    @After(value = "execution(* *..*.*Service.get*(..))")
    public void commitTrans() {
        System.out.println("提交事务");
    }

    //    环绕通知方法
    @Around(value = "execution(* *..*.*Service.get*(..))")
    public void around(ProceedingJoinPoint point) throws Throwable {
        System.out.println("开启日志");//假设的切面方法
        point.proceed();//切入点的代理对象
        System.out.println("提交日志");//假设的切面方法
    }
}
package com.swpu.aspect;
复制代码
    <bean id="transationAspect" class="com.swpu.aspectJ.TransationAspect"></bean>
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
添加注解扫描

  xml形式:

控制层同上,切面层取消方法头部注解,xml文件换用自定义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:context="http://www.springframework.org/schema/context"
       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/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">


    <context:component-scan base-package="com.swpu"/>

    <!--    **********测试AOP  XML方式***************-->
    <!--            切入点简写方式(根据个人情况简写):* *..*.*Service.get*(..)
                        public void com.swpu.service.BookService.getAllBooks()
                        public:不写
                        void:* 即无论任何返回值类型都可以
                        com.swpu.service包:包名一般都是只有最后一个包不同,*..*\
                        BookService类:*Service 表示任何名称以Service结尾的类都可以
                        getAllBooks():get*(..) 表示指定类下的名称为get开头的所有方法都可以。参数为任意参数
       -->
<!--        ①自定义切面类对象-->
        <bean id="transationAspectXml" class="com.swpu.aspectJ.TransationAspeceXml"/>
        <aop:config>
<!--            ②将自定义切面类对象引入AOP的设置中-->
            <aop:aspect ref="transationAspectXml">
<!--                ③使用自定义切面AOP(通知+切入点)通知:如何使用切面。切入点:在哪里使用切面-->
<!--    前置通知-->
                <aop:before method="startTrans" pointcut="execution(public void com.swpu.service.BookService.getAllBooks())"></aop:before>
<!--    后置通知-->
                <aop:after-returning method="commitTrans" pointcut="execution(* *..*.*Service.get*(..))"></aop:after-returning>
<!--                测试其他通知-->
<!--     最终通知:报错也执行 -->
                <aop:after method="commitTrans" pointcut="execution(* *..*.*Service.get*(..))"></aop:after>
<!--     异常通知:报错才执行 -->
                <aop:after-throwing method="commitTrans" pointcut="execution(* *..*.*Service.get*(..))"></aop:after-throwing>
<!--     环绕通知:之前+之后  在transationAspect类自定义环绕方法around-->
                <aop:around method="around" pointcut="execution(* *..*.*Service.get*(..))"></aop:around>
            </aop:aspect>
        </aop:config>


    <!--    **********测试AOP  注解方式***************-->
<!--    <bean id="transationAspect" class="com.swpu.aspectJ.TransationAspect"></bean>-->
<!--    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>-->
</beans>
先新建java类com.swpu.aspectJ.TransationAspeceXml,appcontext.xml内容如下
复制代码

其中methon爆红,直接more action内选择创建方法即可,结果如下:

 

复制代码
package com.swpu.aspectJ;

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

public class TransationAspeceXml {
    public void startTrans(JoinPoint joinPoint) throws Throwable {
        System.out.println("开启事务");
    }

    public void commitTrans(JoinPoint joinPoint) throws Throwable {
        System.out.println("提交事务");
    }

    public void around(ProceedingJoinPoint point) throws Throwable {
        System.out.println("开启日志");//假设的切面方法
        point.proceed();//切入点的代理对象
        System.out.println("提交日志");//假设的切面方法
    }
}
TransationAspeceXml
复制代码

 

 

格式参考:

复制代码
    <!--    ①自定义切面类对象-->
    <bean id="切面类" class="com.swpu.aspectJ.切面类"/>
    <aop:config>
<!--                ②将自定义切面类对象引入AOP的设置中-->
        <aop:aspect ref="transationAspect">
<!--                    ③使用自定义切面AOP(通知+切入点)通知:如何使用切面。切入点:在哪里使用切面-->
<!--            前置通知-->                                        切入点格式1
            <aop:before(通知类型) method="测试方法" pointcut="execution(public void com.swpu.service.BookService.getAllBooks())"></aop:before>
<!--            后置通知-->                                                切入点格式2
            <aop:after-returning(通知类型) method="测试方法" pointcut="execution(* *..*.*Service.get*(..))"></aop:after-returning>
        </aop:aspect>
    </aop:config>
xml自定义AOP格式参考
复制代码

 

 

 

学习博客:

Spring AOP详解  ,Spring——AOP相关概念

【Over】

posted @   Renhr  阅读(27)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
· 零经验选手,Compose 一天开发一款小游戏!
点击右上角即可分享
微信分享提示