zoukankan      html  css  js  c++  java
  • Spring框架——AOP面向切面编程


    简介

    AOP(面向切面编程):是一种新的方法论,是对传统OOP(面向对象编程)的补充。

    AOP编程时,仍然需要定义公共功能,但可以明确的定义这个功能在哪里,以什么方式应用,并且不必修改受影响的类。这样一来横切关注点就被模块化到特殊的对象(切面)里。

    AOP的好处:

    每个事物逻辑位于一个位置,代码不分散,便于维护和升级。

    业务模块更简洁,只包含核心业务的代码。

    横切关注点:
    这里写图片描述


    AOP练习

    Aop关于加减乘除的练习:

    定义一个算法接口,含有4个方法,加减乘除。

    public interface ArithmeticCalculator(){
        //加
        double add(double a,double b);
        //减
        double sub(double a,double b);
        //乘
        double mul(double a,double b);
        //除
        double div(double a,double b);
    }

    Aop思想:

    public void before(double a ,double b){
    System.out.println(a+"and"+b);
    }
    
    public void after(result){
    System.out.println("结果是"+result);
    }
    
    public double sub(double a, double b){
    before(a,b);
    double result=a+b;
    after(result);
    return result;
    }

    但是,这样做是有一些弊端存在的,比如:
    代码混乱:
    越来越多的非业务需求(日志和验证等)加入后,原有的业务方法急剧膨胀,每个方法在处理核心逻辑的同时还必须兼顾其他多个关注点。

    代码分散:
    以日志需求为例,只是为了满足这个单一需求,就不得不在多个模块(方法)里多次重复相同的日志代码,如果日志需求发生变化,必须修改所有模块。

    那么,如何解决这些问题呢?

    这就需要使用Spring的动态代理模式来完成了。


    使用动态代理解决问题

    代理设计模式的原理:使用一个代理将对象包装起来,然后用该代理取代原始对象,任何对原始对象的调用都要通过代理,代理对象决定是否以及何时将方法调用转到原始对象上。

    这里写图片描述


    Spring AOP

    用AspectJ注解声明切面

    切面:带有@Aspect注解的Java类

    通知:是标注有以下5种注解的简单的Java方法

    @Before:前置通知,在方法执行之前执行

    @After:后置通知,在方法执行之后执行

    @AfterReturning:返回通知,在方法返回结果之后执行

    @AfterThrowing:异常通知,在方法抛出异常之后 @Around:环绕通知,围绕着方法执行

    前置后置通知

    前置通知:在方法执行之前执行的通知
    前置通知使用: @Before , @After注解,并将切入点表达式的值作为注解值。

    利用方法签名编写AspectJ切入点表达式

    最典型的切入点表达式是根据方法的签名来匹配各种方法:
    这里写图片描述


    指定切面的优先级

    指定切面的优先级:
    在同一个连接点上应用不止一个切面时,除非明确指定,否则它们的优先级是不确定的。
    切面的优先级可以通过实现Ordered接口或利用@Order注解指定。

    实现Ordered接口,getOrder()方法的返回值越小,优先级越高。

    若使用@Order注解,序号出现在注解中。

    @Aspect
    @Order(0)
    public class CalculaotorValidationAspect
    
    @Aspect
    @Order(1)
    public class CalculatorLoggingAspect

    基于XML的配置声明切面

    基于XML声明切面:

    当使用XML声明切面时,需要在<beans>根元素中导入aop Schema

    在Bean配置文件中,所有的Spring AOP配置都必须定义在<aop:config>元素内部。对于每个切面而言,都要创建一个<aop:aspect>元素来为具体的切面实现引用后端Bean实例。

    使用<aop:pointcut>来配置切点,通知元素需要用<aop:before>等元素,method属性指定切面类中通知方法的名称。


    Spring实例练习

    了解了这些Spring的概念知识后,必须要有一个好的例子来理解,下面就以一个简单的小例子来举例子说明。

    定义一个实体类User,实现它属性的set,get方法:

    public class User {
        private int id;
        private String uname;
        private String pwd;
        private int score;
        public int getId() {
            return id;
        }
        public void setId(int id) {
            this.id = id;
        }
        public String getUname() {
            return uname;
        }
        public void setUname(String uname) {
            this.uname = uname;
        }
        public String getPwd() {
            return pwd;
        }
        public void setPwd(String pwd) {
            this.pwd = pwd;
        }
        public int getScore() {
            return score;
        }
        public void setScore(int score) {
            this.score = score;
        }
    }

    定义一个接口ScoreService,接口中定义一个登陆方法:

    import com.jredu.aop.entity.User;
    
    public interface ScoreService {
    
        /**
         * 登录
         * @param user
         * @return
         */
        User login(User user);
    
    }

    定义一个类ScoreServiceImpl,实现ScoreService 接口中的方法:

    import org.springframework.stereotype.Component;
    
    import com.jredu.aop.entity.User;
    import com.jredu.aop.service.ScoreService;
    @Component("score")
    public class ScoreServiceImpl implements ScoreService{
    
        /**
         * 登录 
         */
        @Override
        public User login(User user) {
            // TODO Auto-generated method stub
            System.out.println("登录成功!");
            return user;
        }
    
    }

    在applicationContext-aop2.xml中依赖注入user,并配置扫描,配置切面等。

    <?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:p="http://www.springframework.org/schema/p"
        xmlns:aop="http://www.springframework.org/schema/aop"
        xmlns:context="http://www.springframework.org/schema/context"
        xmlns:mvc="http://www.springframework.org/schema/mvc"
        xmlns:util="http://www.springframework.org/schema/util"
        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
            http://www.springframework.org/schema/util
            http://www.springframework.org/schema/util/spring-util.xsd
            http://www.springframework.org/schema/aop
            http://www.springframework.org/schema/aop/spring-aop.xsd
            http://www.springframework.org/schema/mvc
            http://www.springframework.org/schema/mvc/spring-mvc.xsd">
              <!-- 自动扫描标签 -->
         <context:component-scan base-package="com.jredu.aop">
         </context:component-scan> 
         <bean
            id="user" class="com.jredu.aop.entity.User"
            p:id="1"
            p:uname="张三"
            p:pwd="123456"
            p:score="0"
         />
         <bean 
            id="springAspect" class="com.jredu.aop.aspect.SpringAspect"
         />
         <!-- 配置切面 -->
         <aop:config>
            <!-- 配置切点 -->
            <aop:pointcut expression="execution(* com.jredu.aop.service.ScoreService.login(..))" id="pointcut"/>
            <!-- 配置切面 -->
            <aop:aspect ref="springAspect">
                <aop:around method="around" pointcut-ref="pointcut"/>
                <aop:after-returning method="afterReturning" pointcut-ref="pointcut" returning="obj"/>
            </aop:aspect>
         </aop:config>
    
    </beans>

    定义切面类SpringAspect,在切面中定义相关方法。

    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.ProceedingJoinPoint;
    
    import com.jredu.aop.entity.User;
    
    public class SpringAspect {
    
        /**
         * 执行前
         * @param point
         *//*
        public void before(JoinPoint point){
            String method = point.getSignature().getName();
            System.out.println("before method:"+method);
        }*/
    
        /**
         * 执行后
         * @param point
         * @throws Throwable 
         */
        public User around(ProceedingJoinPoint point) throws Throwable{
            String method = point.getSignature().getName();
            System.out.println("before method:"+method);
            //调用目标方法前
            User user = (User) point.proceed();
            //调用目标方法后
            System.out.println("原来的用户积分:"+user.getScore());
            System.out.println("after method:"+method);
            user.setScore(user.getScore()+100);
            return user;
    
        }
    
        /**
         * 最终返回结果
         * @param point
         * @param obj
         */
        public void afterReturning(JoinPoint point,Object obj){
            String method = point.getSignature().getName();
            System.out.println("afterReturning method:"+method);
            User user = (User) obj;
            System.out.println("现在用户的积分:"+user.getScore());
        }
    }

    测试类:

    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    import com.jredu.aop.entity.User;
    import com.jredu.aop.service.ScoreService;
    
    public class ScoreTest {
    
        public static void main(String[] args) {
            ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext-aop2.xml");
            User user = (User) app.getBean("user");
            ScoreService service =(ScoreService) app.getBean("score");
            service.login(user);
        }
    }

    项目完成后的项目截图:
    这里写图片描述

  • 相关阅读:
    codeforces 980A Links and Pearls
    zoj 3640 Help Me Escape
    sgu 495 Kids and Prizes
    poj 3071 Football
    hdu 3853 LOOPS
    hdu 4035 Maze
    hdu 4405 Aeroplane chess
    poj 2096 Collecting Bugs
    scu 4444 Travel
    zoj 3870 Team Formation
  • 原文地址:https://www.cnblogs.com/aixing/p/13327666.html
Copyright © 2011-2022 走看看