zoukankan      html  css  js  c++  java
  • spring(二):简单阐述springAOP的实现原理

    前言:

      AOP技术利用一种称为横切的技术,解剖封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,

    这样就能减少系统的重复代码,降低模块间的耦合度,并有利于未来的可操作性和可维护性。


     

    实现原理:

      AOP通俗的来说就是在某个方法执行前后插入一些代码,非常有名的就是日志功能了。但是为了代码的耦合性又不能把这些代码写死到

    某个方法中,把这些代码提取出来封装到一个模块中,由AOP指定插入位置。

      springAOP实现原理用到了代理模式和反射。虽然我们自己没法造轮子写一个AOP,但是这里举一个代码例子模拟AOP如何工作的,使用的

    是JDK的动态代理。

     

    1.准备一个pojo类

      Account.java

    package com.cnblogs.aop.pojo;
    /**
     * 简单模拟银行账户
     *
     */
    public class Account {
        // 卡号
        private Long id;
        // 姓名    
        private String name;
        //余额
        private double balance;
        
        public Account() {
            super();
            // TODO Auto-generated constructor stub
        }
        
        public Account(Long id, String name, double balance) {
            super();
            this.id = id;
            this.name = name;
            this.balance = balance;
        }
    
        public Long getId() {
            return id;
        }
        public void setId(Long id) {
            this.id = id;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public double getBalance() {
            return balance;
        }
        public void setBalance(double balance) {
            this.balance = balance;
        }
    }

     

    2.准备一个接口,可以在这个接口中定义许多服务方法。这里仅一个存钱的方法

     AccountService.java

    package com.cnblogs.aop.theory.service;
    
    public interface AccountService {
        /**
         * 存钱  
         * @param money
         */
        public abstract void save(double money);
    }

    它的实现类AccountServiceImpl.java

    package com.cnblogs.aop.theory.service.serviceImpl;
    
    import com.cnblogs.aop.pojo.Account;
    import com.cnblogs.aop.theory.service.AccountService;
    
    public class AccountServiceImpl implements AccountService{
        private Account account;
        
        public AccountServiceImpl(Account account) {
            this.account = account;
        }
        
        @Override
        public void save(double money) {
            account.setBalance(account.getBalance() + money);
            System.out.println("当前余额为: " + account.getBalance() );
        }
    
    }

     

    3.准备切面类,这个就是需要插入方法前后的那些代码。

    Log.java

    package com.cnblogs.aop.theory.log;
    
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    /**
     * 日志功能
     * 记录操作时间
     *
     */
    public class Log {
        
        
        public void before(){
            System.out.println("操作开始时间: " + new SimpleDateFormat().format(new Date()));
        }
        
        public void after(){
            System.out.println("操作结束时间: " + new SimpleDateFormat().format(new Date()));
        }
    }

     

     

    4.代理类。重点部分

    package com.cnblogs.aop.theory.proxy;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    /**
     * 动态代理
     *
     */
    public class DynAccountService implements InvocationHandler{
        // 目标对象    
        private Object target;
        
        public DynAccountService(Object target) {
            this.target = target;
        }
        
        /**
         * 给目标对象生成代理对象
         */
        public Object bind(){
            return Proxy.newProxyInstance(this.target.getClass().getClassLoader(), 
                    this.target.getClass().getInterfaces(), this);
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            // 利用反射获得日志对象
            Class<?> log = Class.forName("com.cnblogs.aop.theory.log.Log");
            // 获得before()
            Method before = log.getMethod("before");
            // 获得after()
            Method after = log.getMethod("after");
            
            // 添加额外功能
            before.invoke(log.newInstance());
            // 运行目标对象方法
            method.invoke(this.target, args);
            // 添加额外功能
            after.invoke(log.newInstance());
            
            return null;
        }
    }

    (1):static Object newProxyInstance(ClassLoader<?>  loader,Class(?)[] interface, InvocationHandler handler)

    1.loader: 目标对象的类加载器

    2.interface:目标对象实现的接口

    3.handler:事件处理,执行目标对象的方法时,会触发事件处理器的invoke方法,并把执行目标对象方法传入invoke中

    (2):在invoke方法中利用反射获得切面类日志对象,为的是代理类和日志类解耦。

     

      

    5.测试方法和结果

    package com.cnblogs.aop.theory.jtest;
    
    import com.cnblogs.aop.pojo.Account;
    import com.cnblogs.aop.theory.proxy.DynAccountService;
    import com.cnblogs.aop.theory.service.AccountService;
    import com.cnblogs.aop.theory.service.serviceImpl.AccountServiceImpl;
    
    public class TheoryTest {
        public static void main(String[] args) {
            Account account = new Account(6217L, "zs", 5000.0);
           // 获得代理对象
            AccountService service = (AccountService) new DynAccountService(new AccountServiceImpl(account)).bind();
         // 执行目标对象的方法 service.save(
    1000); } }

     

    结果:

      操作开始时间: 19-5-27 下午7:05
      当前余额为: 6000.0
      操作结束时间: 19-5-27 下午7:05

     

     

  • 相关阅读:
    在vmware workstation10上安装ubuntu14.04,出现以下问题
    经典句
    杂文
    matlab里textread出现错误“Trouble reading floating point number from file (row 1, field 1)”
    Nginx配置杂记(转)
    mysql经典案例分析
    Git查看、删除、重命名远程分支和tag(转)
    nginx下开启pathinfo模式
    ubuntu-apache如何解决跨域资源访问
    c语言插入排序
  • 原文地址:https://www.cnblogs.com/yangji0202/p/10932403.html
Copyright © 2011-2022 走看看