zoukankan      html  css  js  c++  java
  • 基于标注的AOP面向切面编程

    1.什么是AOP

       Aspect  Orientied   Programming的简称,即 面向(方面)切面编程 ,不改变一个组件源代码的情况下 可以对组件功能进行增强。

     例如:servlet中的过滤器,继承,装饰者模式,代理模式,

    JDK 的代理 必须有统一接口 目标类和代理类 兄弟关系
    CGLIB 的代理 底层是继承 目标类和代理类 父子关系

    2.AOP 中涉及到核心概念
       ###切面 Aspect 抽取共通业务逻辑到一个类中 每个共通业务逻辑就是一个切面方法
       定义了共通业务逻辑的类叫切面类 使用切面类创建的对象 叫切面对象
       连接点 JoinPoint 添加切面逻辑的一个位置 一般这个就是一个方法
       ###切点 Pointcut 一堆连接点的集合 后面会讲表达式的写法
       目标对象 Target 那个对象需要加共通业务逻辑
       代理对象 Proxy 被增强了的目标对象就是代理对象
       ###通知 Advice 时机 (目标方法执行之前 之后 执行前后 出异常)

    切面 通知 切点 (把共通的业务逻辑 在合适的时间点 加入到对应的方法上)

    6.切点表达式的写法
    6.1 bean 名字限定表达式
        bean(容器中组件的id) 组件的id可以使用统配
    6.2 类型限定表达式
       within(限定的类型) 限定的类型 是通过包名.类名
       within(com.xdl.service.XdlUserService) 对 XdlUserService 类型做限定
       XdlUserService中所有方法都切入共通逻辑
       within(com.xdl.service.*) 对service 包下 所有类型 都切入对应的逻辑
       within(com.xdl.*.*) xdl 直接子包下的类型 切入对应的逻辑
       within(com.xdl..*) xdl 包 以及子包下的类型 切入对应的逻辑
    6.3 方法限定表达式
       execution(权限修饰 方法返回值类型 方法名(参数) throws 异常)
       返回值类型 方法名(参数) 是必须的
       execution(void user*()) 所有的返回void 方法名以user开头的无参的方法
       被切入逻辑

    7.通知的五种类型
       <aop:before 前置通知 目标方法执行之前执行
       <aop:after 最终通知 目标方法执行之后 最终肯定会执行
       <aop:after-returning 后置通知 目标方法执行之后 如果目标方法出现异常 则不执行
       <aop:after-throwing 异常通知 目标方法执行出现异常 就会调用异常通知
       <aop:around 环绕通知 目标方法执行前后都会调用

    8. 五种通知对应的标注
       <aop:before 前置通知 @Before
       <aop:after 最终通知 @After
       <aop:after-returning 后置通知 @AfterReturning
       <aop:after-throwing 异常通知 @AfterThrowing
       <aop:around 环绕通知 @Around

    例子:

    首先拷贝一个配置文件到类路径下

    <?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:jdbc="http://www.springframework.org/schema/jdbc" xmlns:jee="http://www.springframework.org/schema/jee"
        xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop"
        xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:util="http://www.springframework.org/schema/util"
        xmlns:jpa="http://www.springframework.org/schema/data/jpa"
        xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd
        http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-4.1.xsd
        http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.1.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.1.xsd
        http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.1.xsd
        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd
        http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.1.xsd">
        <!-- 组件扫描 -->
        <context:component-scan base-package="cn.com"></context:component-scan>
        <!-- 通过配置织入@Aspectj切面-->    
        <aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>
        
        
    </beans>

    好了,开始写代码:

    首先添加一个model类;

    import java.io.Serializable;
    
    public class BankAccountModel implements Serializable {
        private static final long serialVersionUID = 1L;
        private int id;
        private String acc_no;
        private String acc_password;
        private double acc_money;
    
        public BankAccountModel() {
            super();
        }
    
        public BankAccountModel(int id, String acc_no, String acc_password, double acc_money) {
            super();
            this.id = id;
            this.acc_no = acc_no;
            this.acc_password = acc_password;
            this.acc_money = acc_money;
        }
    
        public int getId() {
            return id;
        }
    
        public void setId(int id) {
            this.id = id;
        }
    
        public String getAcc_no() {
            return acc_no;
        }
    
        public void setAcc_no(String acc_no) {
            this.acc_no = acc_no;
        }
    
        public String getAcc_password() {
            return acc_password;
        }
    
        public void setAcc_password(String acc_password) {
            this.acc_password = acc_password;
        }
    
        public double getAcc_money() {
            return acc_money;
        }
    
        public void setAcc_money(double acc_money) {
            this.acc_money = acc_money;
        }
    
        public static long getSerialversionuid() {
            return serialVersionUID;
        }
    
        @Override
        public String toString() {
            return "BankAccountModel [id=" + id + ", acc_no=" + acc_no + ", acc_password=" + acc_password + ", acc_money="
                    + acc_money + "]";
        }
    
    }
    View Code

    来一个接口和一个实现类

    public interface BankAccountDao {
        
        int addAccount(BankAccountModel ba);//添加
        
        BankAccountModel selectAccountByID(int id); //查询
        
        
    }
    @Repository("bankDao")//持久层标注
    public class BankAccountDaoIMP implements BankAccountDao {
    
        @Override
        public int addAccount(BankAccountModel ba) {
            System.out.println("正在添加......");
            return 0;
        }
    
        @Override
        public BankAccountModel selectAccountByID(int id) {
            System.out.println("正在查询......");
            return null;
        }
    
    }

    然后再写一个service层,(好吧,其实是可以不用写的,毕竟没有真正实现功能)

    @Service("bankService")//spring中service层的标注1
    public class BankAccountService {
        @Autowired
        private BankAccountDao dao;
    
        public int addAccount(BankAccountModel ba) {
            return dao.addAccount(ba);
        }
    
        public BankAccountModel selectAccountByID(int id) {
            return dao.selectAccountByID(id);
        }
        
        public void login(){
            
            System.out.println("登录中....");
            if(1==2){
                throw new RuntimeException("登录方法出现异常!!");//这一部分未来测试专门让他出异常的,可以忽略哦
            }
            
        }
        
        public void register(){
            System.out.println("正在注册....");
        }
    }

    最后可以来一个aspect类了

    @Component//通用层标注
    @Aspect  //基于aop的标注
    public class BankAccountAspect {
    
        /*
         * @Before("bean(bankA*)") public void beforeUserLog(){ System.out.println(
         * "####    ####"); }
         */
    
        @Before("within(cn.com.service..*)")
        public void beforeUserLog() {
            System.out.println("####    ####");
        }
    
        /* 异常的参数必须出现在最后面 */
        @AfterThrowing(pointcut = "within(cn.com.service..*)", throwing = "e")
        public void beforeAround(JoinPoint j, Exception e) {
            System.out.println("正在记录异常信息..." + e.getMessage() + ":" + j.getSignature());
        }
        
        /*统计方法执行时间*/
        @Around("execution(void *())")
        public Object countTime(ProceedingJoinPoint pjp) throws Throwable{//此处的方法必须返回为Object,否则环绕的目标方法中如果有返回值就会丢弃
            long stat=System.currentTimeMillis();
            //执行目标方法 
            Object proceed = pjp.proceed();//使用proceed()方法来执行目标方法
            
            
            long end = System.currentTimeMillis();
            System.out.println("方法执行的毫秒数是:" + (end-stat));
            return proceed;
        } 
    
    }



    测试代码:

                public static void main(String[] args) {
                ApplicationContext app=new ClassPathXmlApplicationContext("applicationContext.xml");
                BankAccountService user=app.getBean("bankService",BankAccountService.class);
                System.out.println(user.addAccount(new BankAccountModel(12, "13", "12324", 123)));
                System.out.println(user.selectAccountByID(2));
                }


    测试结果:

        #### ####
        正在添加......
        0
        #### ####
        正在查询......
        null

     
  • 相关阅读:
    【转】Fiddler 教程
    【转】java中三个类别加载器的关系以及各自加载的类的范围
    【转】HTTP协议详解
    【转】Google是如何做代码审查的?
    JSP页面的三种include方式
    forward和sendRedirect的差别
    cxf方式实现WebService的简单实例
    Pushlet简单入门实例
    Java学习(二十三):log4j日志打印
    PL/SQL相关问题解决办法汇总
  • 原文地址:https://www.cnblogs.com/hx1098/p/9350129.html
Copyright © 2011-2022 走看看