栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

【SSM】Spring系列——AOP面向切面编程1

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

【SSM】Spring系列——AOP面向切面编程1

文章目录
  • 03 AOP面向切面编程
    • 3.1 AOP概述
    • 3.2 面向切面编程对有什么好处
    • 3.3 模拟AOP框架实现
      • 3.3.1 代码实现版本一
      • 3.3.2 代码实现版本二
      • 3.3.3 代码实现版本三
      • 3.3.4 代码实现版本四
      • 3.3.5 代码实现版本五
    • 3.4 Spring的AOP通知类型(了解)

03 AOP面向切面编程 3.1 AOP概述
  • AOP(Aspect Orient Programming),意为:面向切面编程,可通过运行期动态代理实现程序功能的统一维护的一种技术。
  • AOP 是 Spring 框架中的一个重要内容。
  • 面向切面编程是从动态角度考虑程序运行过程。
  • AOP 底层,就是采用动态代理模式实现的。
  • 采用了两种代理:JDK 的动态代理,与 CGLIB的动态代理。
  • 利用 AOP 可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

何为面向切面编程?

  • 面向切面编程,就是将交叉业务逻辑封装成切面,利用 AOP 容器的功能将切面织入到主业务逻辑中。
  • 所谓交叉业务逻辑是指,通用的、与主业务逻辑无关的代码,如安全检查、事务、日志、缓存等。
  • 若不使用 AOP,则会出现代码纠缠,即交叉业务逻辑与主业务逻辑混合在一起。这样, 会使主业务逻辑变的混杂不清。
  • 例如,转账,在真正转账业务逻辑前后,需要权限控制、日志记录、加载事务、结束事务等交叉业务逻辑,而这些业务逻辑与主业务逻辑间并无直接关系。但它们的代码量所占比重能达到总代码量的一半甚至还多。它们的存在,不仅产生了大量的“冗余”代码,还大大干扰了主业务逻辑—转账。
3.2 面向切面编程对有什么好处

1.减少重复;

2.专注业务;

注意:面向切面编程只是面向对象编程的一种补充。用 AOP 减少重复代码,专注业务实现。

3.3 模拟AOP框架实现

主要的目的是进行业务逻辑与切面的解耦合。完全分离业务逻辑和切面。

分为五个版本:

1)版本一:业务和切面紧耦合在一起。

2)版本二:子类代理实现切面功能增强。

3)版本三:使用静态代理分离业务。

4)版本四:使用静态代理分离业务和切面。

5)版本五:使用动态代理优化业务和切面的解耦合。

3.3.1 代码实现版本一

业务和切面紧耦合在一起。

public class BookServiceImpl { 
    public void buy(){  
        try {     
            //切面部分:事务处理    
            System.out.println("事务开启......");   
            //主业务实现    
            System.out.println("图书购买业务的实现............");    
            //切面部分:事务处理     
            System.out.println("事务提交......");   
        } catch (Exception e) {   
            //切面部分:事务处理 
            System.out.println("事务回滚.........."); 
        }  
    } 
} 
3.3.2 代码实现版本二

子类代理实现切面功能增强

public class BookServiceImpl {  
    public void buy(){  
        //实现主业务功能  
        System.out.println("图书购买业务的实现..........."); 
    }
}
public class SubBookServiceImpl extends BookServiceImpl {   
    //重写父类的业务方法,增强切面(事务)的功能 
    @Override 
    public void buy() { 
        try {     
            //切面部分:   
            System.out.println("事务开启................");   
            super.buy();    
            //切面部分:  
            System.out.println("事务提交................");  
        } catch (Exception e) {   
            //切面部分:   
            System.out.println("事务回滚................"); 
        } 
    } 
} 
3.3.3 代码实现版本三

使用静态代理分离业务

public interface Service {   
    public void buy(); 
}

public class BookServiceImpl implements Service { 
    @Override 
    public void buy() {     
        //只要完成主业务功能就行  
        System.out.println("图书购买业务实现...............");
    }
}

public class ProductServiceImpl implements Service{
    @Override  
    public void buy() {    
        System.out.println("商品购买业务实现..............");
    }
}

public class Agent implements Service {
    //上接口上灵活,目标对象灵活切换  
    public Service target;  
    //使用构造方法传入目标对象  
    public Agent(Service target){  
        this.target = target; 
    }  
    @Override  
    public void buy() {   
        try {  
            //切面功能实现   
            System.out.println("事务开启...........");  
            //业务功能实现    
            target.buy();   
            //切面功能实现    
            System.out.println("事务提交");   
        } catch (Exception e) {    
            System.out.println("事务回滚............."); 
        } 
    }
}

public class MyTest03 {  
    @Test 
    public void test03(){ 
        Service service = new Agent(new ProductServiceImpl()); 
        service.buy();  
    } 
}
3.3.4 代码实现版本四

使用静态代理分离业务和切面

public interface AOP { 
    default void before(){}  
    default void after(){}   
    default void exception(){} 
}
public class TransAop implements AOP { 
    @Override
    public void before() { 
        System.out.println("事务开启............"); 
    } 
    @Override   
    public void after() { 
        System.out.println("事务提交...........");  
    } 
    @Override  
    public void exception() { 
        System.out.println("事务回滚...........");  
    }
}
public class LogAop implements AOP {
    @Override 
    public void before() {  
        System.out.println("前置日志输出 ............."); 
    } 
}


public interface Service {   
    public void buy(); 
}
public class BookServiceImpl implements Service { 
    @Override 
    public void buy() {     
        //只要完成主业务功能就行  
        System.out.println("图书购买业务实现...............");
    }
}
public class ProductServiceImpl implements Service{
    @Override  
    public void buy() {    
        System.out.println("商品购买业务实现..............");
    }
}


public class Agent implements Service{   
    public Service target;
    //为了灵活的切换业务,上接口   
    public AOP aop; 
    //为了灵活的切换切面,上接口
    public Agent(Service target,AOP aop){    
        this.target = target;    
        this.aop = aop;  
    }   
    @Override  
    public void buy() {  
        try {  
            //切面功能  
            aop.before();
            //哪个实现类来了,调用哪个实现类的功能  
            //业务功能  
            target.buy();    
            //切面功能
            aop.after();  
        } catch (Exception e) {  
            aop.exception(); 
        } 
    } 
}

public class MyTest04 { 
    @Test 
    public void test03(){   
        Service agent = new Agent(new ProductServiceImpl(),new LogAop()); 
        agent.buy();  
    }
} 
3.3.5 代码实现版本五

完全的解耦了业务与服务性质的业务(切面),切换功能和方面更灵活。

但是只能是buy()一个功能,如果再代理的功能多了,就不行了,解决方案是动态代理模式。

public class ProxyFactory { 
    //通过方法参数传入目标对象和切面对象  
    public static Object getAgent(Service target,AOP aop){  
        return Proxy.newProxyInstance(
            //类加载
            target.getClass().getClassLoader(), 
            //目标对象实现的所有接口
            target.getClass().getInterfaces(),
            //代理功能实现
            new InvocationHandler() {     
                @Override    
                public Object invoke(
                    //生成的代理对象
                    Object proxy, 
                    //正在被调用的目标方法bug(),show()
                    Method method, 
                    //目标方法的参数
                    Object[] args) throws Throwable {             
                    Object obj=null;    
                try {           
                    aop.before(); 
                    //灵活的进行切面功能切换
                    obj = method.invoke(target,args); 
                    //灵活的进行业务功能切换        
                    aop.after(); 
                    //灵活的进行切面功能切换  
                } catch (Exception e) {       
                    aop.exception();  
                    //灵活的进行切面功能切换 
                }     
            return obj;//目标方法的返回值  
            }         
        });
        //返回动态代理对象 
    }
}
public class MyTest05 { 
    @Test  
    public void test03(){   
        //得到代理对象  
        Service agent = (Service) ProxyFactory.getAgent(new ProductServiceImpl(),new TransAop());   
        Service agent1 = (Service) ProxyFactory.getAgent(agent,new LogAop());     agent1.buy();  
    } 
}

这个解决方案很好的解决了业务和切面的紧耦合。可以灵活的进行业务的切换,可以灵活的进行切面的切换。可以嵌套切面的处理。

3.4 Spring的AOP通知类型(了解)

Spring支持AOP的编程,常用的有以下几种:

1)Before通知:在目标方法被调用前调用,涉及接口org.springframework.aop.MethodBeforeAdvice;
2)After通知:在目标方法被调用后调用,涉及接口为org.springframework.aop.AfterReturningAdvice;
3)Throws通知:目标方法抛出异常时调用,涉及接口org.springframework.aop.ThrowsAdvice;
4)Around通知:拦截对目标对象方法调用,涉及接口为org.aopalliance.intercept.MethodInterceptor。

案例:

LogAdvice.java 
    public class LogAdvice implements MethodBeforeAdvice {	
        private static SimpleDateFormat sf = new SimpleDateFormat("yyyy年MM月dd日");
        @Override	
        public void before(Method m, Object[] args, Object arg2)			
            throws Throwable {		
            System.out.println("n[系统日志]["+sf.format(new Date())
                               +"]"+m.getName()
                               +"("+Arrays.toString(args)
                               +")");
        }
    }
          

BookService .java

public interface BookService {
    public boolean buy(String userName,String bookName,double price);
    public void comment(String userName,String comments);
}

BookServiceImpl .java

public class BookServiceImpl implements BookService {	
    	
    @Override
    public boolean buy(String userName, String bookName, double price) {
        System.out.println("业务buy开始执行");		
        System.out.println(userName+"购买了图书"+bookName);		
        System.out.println(userName+"增加积分"+(int)(price/10));	
        System.out.println("图书购买完毕,向物流下单....");			
        System.out.println("业务buy结束");	
        return true;	
    }	
    
    @Override
    public void comment(String userName, String comments) {	
        System.out.println("业务comment开始执行");	
        System.out.println(userName+"发表图书评论"+comments);
        System.out.println("业务comment执行结束");	
    }
}

applicationContext.xml

 



	
    
    	
        com.oracle.aop.biz.BookService
    	
    
    	
        		
            logAdvice	
        	
    
    
    

TestAOP.java

public class TestAOP {	
    @Test	
    public void testAop(){	
        ApplicationContext context= new ClassPathXmlApplicationContext("applicationContext.xml");
        BookService bookservice=(BookService)context.getBean("bookService");
        bookservice.buy("高志水", "CMMi实务手册", 50);	
        bookservice.comment("王筝","《盗墓笔记》一点都不恐怖,很好看!");	
    }
}

Spring的AOP利用一种称为“横切”的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其名为“Aspect”,即方面。所谓“方面”,

简单地说,就是将那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可操作性和可维护性。

AOP代表的是一个横向的关系,如果说“对象”是一个空心的圆柱体,其中封装的是对象的属性和行为;那么面向方面编程的方法,就仿佛一把利刃,将这些空心圆柱体剖开,以获得其内部的消息。而剖开的切面,也就是所谓的“方面”了。然后它又以巧夺天功的妙手将这些剖开的切面复原,不留痕迹。

总结:AOP的核心思想就是“将应用程序中的商业逻辑同对其提供支持的通用服务进行分离。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1023551.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号