zoukankan      html  css  js  c++  java
  • Spring学习之路3-AOP及实现AOP的三种方式

    AOP

    面向切面的程序设计(Aspect-oriented programming,AOP,又译作面向方面的程序设计、剖面导向程序设计)是计算机科学中的一种程序设计思想,旨在将横切关注点与业务主体进行进一步分离,以提高程序代码的模块化程度。通过在现有代码基础上增加额外的通知(Advice)机制,能够对被声明为“切点(Pointcut)”的代码块进行统一管理与装饰,如“对所有方法名以‘set*’开头的方法添加后台日志”。该思想使得开发人员能够将与代码核心业务逻辑关系不那么密切的功能(如日志功能)添加至程序中,同时又不降低业务代码的可读性。面向切面的程序设计思想也是面向切面软件开发的基础。

    Maven 依赖

    <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.9.5</version>
    </dependency>
    

    实现方式一:原生 Spring API 接口

    public interface UserService {
        void add();
        int delete();
        void query();
        int update();
    }
    
    public class UserServiceImpl implements UserService {
        @Override
        public void add() {
            System.out.println("function:add()");
        }
    
        @Override
        public int delete() {
            System.out.println("function:delete()");
            return 0;
        }
    
        @Override
        public void query() {
            System.out.println("function:query()");
        }
    
        @Override
        public int update() {
            System.out.println("function:update()");
            return 0;
        }
    }
    
    //方法执行前的log
    public class BeforeLog implements MethodBeforeAdvice {
    
        @Override
        public void before(Method method, Object[] args, Object target) throws Throwable {
    
            System.err.println("method before log" + target.getClass().getName() + method.getName());
        }
    }
    
    //方法执行后的log
    public class AfterLog implements AfterReturningAdvice {
        @Override
        public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
            System.err.println("method before log" + target.getClass().getName() + "-->" + method.getName() + "---return:" + returnValue);
        }
    }
    
    <?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
           http://www.springframework.org/schema/beans/spring-beans.xsd
           http://www.springframework.org/schema/aop
           http://www.springframework.org/schema/aop/spring-aop.xsd">
    
    
        <bean id="log1" class="com.youzi.log.BeforeLog"/>
        <bean id="log2" class="com.youzi.log.AfterLog"/>
        <bean id="userservice" class="com.youzi.service.UserServiceImpl"/>
    
        <!--配置AOP-->
        <aop:config>
            <aop:pointcut id="pointcut1" expression="execution(int com.youzi.service.UserServiceImpl.*(..))"/>
            <aop:pointcut id="pointcut2" expression="execution(void com.youzi.service.*.add(..))"/>
            <aop:advisor advice-ref="log1" pointcut-ref="pointcut1"/>
            <aop:advisor advice-ref="log2" pointcut-ref="pointcut2"/>
        </aop:config>
    </beans>
    

    execution() 切点函数语法:

    execution(返回类型 包名.类名.方法名(参数类型))
    
    • 也可以用*号表示所有的类型。

    • 类名也可以用*代替表示包下面的所有类

    • *(..):这个星号表示方法名,*号表示所有的方法,括号中是方法的参数,两个点表示任何参数。

    实现方式二:自定义类

    第一种实现方式虽然实现了在方法前或者方法后添加日志,但是每实现一个功能就需要实现一个接口,通过下面的方法可以把这些方法写在一个类中

    public class MethodLog {
        public void beforeMethod() {
            System.out.println("方法执行前");
        }
    
        public void afterMethod() {
            System.out.println("方法执行后");
        }
    }
    
    <?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 http://www.springframework.org/schema/beans/spring-beans.xsd
                               http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
    
        <bean id="MethodLog" class="com.youzi.log.MethodLog"/>
        <bean id="userservice" class="com.youzi.service.UserServiceImpl"/>
    
        <aop:config>
            <aop:aspect ref="MethodLog">
                <aop:pointcut id="poindcut1" expression="execution(* com.youzi.service.*.*(..))"/>
                <aop:before method="beforeMethod" pointcut-ref="poindcut1"/>
                <aop:after method="afterMethod" pointcut-ref="poindcut1"/>
            </aop:aspect>
        </aop:config>
    </beans>
    

    上面的方法虽然简化了代码,但是目前看来不能像第一种方式一样通过反射取到执行方法的信息

    实现方式三:使用注解

    <?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 http://www.springframework.org/schema/beans/spring-beans.xsd
                               http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
    
        <bean id="MethodLog" class="com.youzi.log.MethodLog"/>
        <bean id="userservice" class="com.youzi.service.UserServiceImpl"/>
        <!--在xml中声明使用注解的方式-->
        <aop:aspectj-autoproxy/>
    </beans>
    
    @Aspect	
    public class MethodLog {
        @Before("execution(* com.youzi.service.UserServiceImpl.*(..))")
        public void beforeMethod() {
            System.out.println("方法执行前1");
        }
    
        @After("execution(* com.youzi.service.UserServiceImpl.*(..))")
        public void afterMethod() {
            System.out.println("方法执行后1");
        }
    
        @Around("execution(* com.youzi.service.UserServiceImpl.update(..))")
        public int aroundMethod(ProceedingJoinPoint joinPoint) throws Throwable {
            System.err.println("环绕前");
            System.err.println(joinPoint.getSignature());
            Object proceed = joinPoint.proceed();
            System.err.println("环绕后");
            return Integer.valueOf((Integer) proceed);
        }
    
    }
    

    测试代码统一为

    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    UserService userService = context.getBean("userservice", UserService.class);
    userService.query();
    userService.add();
    userService.delete();
    userService.update();
    
  • 相关阅读:
    如何只通过Sandboxed Solution启动一个定时执行的操作
    创建与SharePoint 2010风格一致的下拉菜单 (续) 整合Feature Custom Action框架
    创建与SharePoint 2010风格一致的下拉菜单
    《SharePoint 2010 应用程序开发指南》第二章预览
    SharePoint 2013 App 开发 (1) 什么是SharePoint App?
    使用Jscex增强SharePoint 2010 JavaScript Client Object Model (JSOM)
    搜索范围的管理
    SharePoint 2010 服务应用程序(Service Application)架构(1)
    SharePoint 2010 服务应用程序(Service Application)架构(2)
    SharePoint 2013 App 开发 (2) 建立开发环境
  • 原文地址:https://www.cnblogs.com/wangjr1994/p/12528806.html
Copyright © 2011-2022 走看看