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

Spring之AOP

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

Spring之AOP

一、AOP介绍

AOP(Aspect Oriented Programming),即面向切面编程,可以说是OOP(Object Oriented Programming,面向对象编程)的补充和完善。就是将交叉业务逻辑封装成切面,利用AOP的功能将切面织入到主业务逻辑中。所谓交叉业务逻辑是指,通用的、与主业务逻辑无关的代码若不使用AOP,则会出现代码纠缠,即交叉业务逻辑与主业务逻辑混合在一起。这样,会使主业务逻辑变的混杂不清。在代码执行过程中,动态嵌入其他代码,叫做面向切面编程。常见的使用场景:日志、事务、数据库操作等。


二、AOP中关键性概念
                术语                                                                        说明
连接点(Joinpoint)

程序执行过程中明确的点,如方法的调用,或者异常的抛出.

注:完成具体的业务逻辑

目标(Target)

被通知(被代理)的对象

注:完成切面编程

通知(Advice)在某种特定的连接点上所执行的动作
代理(Proxy)
将通知应用到目标上所创建的对象(代理=通知+目标)
注:只有代理对象才有AOP功能,而AOP的代码是写在通知的方法里面的
切入点(Pointcut)
多个连接点的集合,将通知应用到哪些连接点
适配器(Advisor)
通知+切入点(相当于必须满足切入点的条件,才会应用通知部分)


三、AOP的实现方式
                                     通知类型                                                说明
前置通知(MethodBeforeAdvice)目标方法执行之前调用
后置通知(AfterReturningAdvice)目标方法执行完成之后调用
环绕通知(MethodInterceptor)目标方法执行前后都会调用方法,且能增强结果
异常处理通知(ThrowsAdvice)目标方法出现异常调用

代理=通知+目标

    创建目标接口和实现类
public interface IBookBiz {
	// 购书
	public boolean buy(String userName, String bookName, Double price);

	// 发表书评
	public void comment(String userName, String comments);
}
public class BookBizImpl implements IBookBiz {

	public BookBizImpl() {
		super();
	}

	public boolean buy(String userName, String bookName, Double price) {
		// 通过控制台的输出方式模拟购书
		if (null == price || price <= 0) {
			throw new PriceException("book price exception");
		}
		System.out.println(userName + " buy " + bookName + ", spend " + price);
		return true;
	}

	public void comment(String userName, String comments) {
		// 通过控制台的输出方式模拟发表书评
		System.out.println(userName + " say:" + comments);
	}

}

前置通知(MethodBeforeAdvice)

创建前置通知类

public class BeforeAdvice implements MethodBeforeAdvice {
    
    @Override
    public void before(Method method, Object[] args, Object target)
            throws Throwable {
        //获取被调用的方法名
        String methodName = method.getName();
        //获取目标方法的类的全路径名
        String className = target.getClass().getName();

        System.out.println("[前置通知]"+className+"."+methodName+
                "执行参数:"+ Arrays.toString(args));

    }
}

配置spring文件中前置配置

定义前置通知

        
            
            
                
                    
                    beforeAdvice
                    
                
            
            
            
                
            
 
 
            
            
                    
                        biz.IBookBiz
                    
            
        

初始化spring.xml上下文并执行目标方法

//1.初始化Spring上下文容器(IOC)
ApplicationContext ac=new ClassPathXmlApplicationContext("spring.xml");
IBookBiz proxy = ac.getBean("proxy", IBookBiz.class);
//调用buy和comment方法时,会将前置通知应用到目标方法上得到代理对象
proxy.buy("李四","西游记",200d);
proxy.comment("李四","好看,名著");

在这里的遵循了里氏替换原则

IBookBiz proxy = ac.getBean("proxy", IBookBiz.class);

        A

   B        C

B和C都实现了A,B和C有一个共同的父类A

 A:IBookBiz        
 B:BookBizImpl  
 C:Proxy      

代理(proxy)也实现了IBookBiz接口

BookBizImpl 实现了IBookBiz接口

所有用父类去接收,而不是用BookBizImpl

错误的方式接收

BookBizImpl proxy=ac.getBean(s:"proxy",BookBizImpl .class);

会出现

 java.lang.ClassCastException: com.sun.proxy.$Proxy4 cannot be cast to 包路径.BookBizImpl

异常

这里相当于

BookBizImpl proxy=(BookBizImpl )proxy

正确方式

IBookBiz bookBiz1=new BookBizImpl();

IBookBiz bookBiz2=new Proxy();

执行结果为 


后置通知(AfterReturningAdvice)

创建后置通知类

public class AfterAdvice implements AfterReturningAdvice {

    
    @Override
    public void afterReturning(Object returnValue, Method method,
                               Object[] args, Object target) throws Throwable {
        //获取目标方法名
        String methodName = method.getName();
        //获取目标方法的类的全路径名
        String className = target.getClass().getName();
        System.out.println("[后置通知]"+className+"."+methodName+
                "执行参数"+ Arrays.toString(args)+"返回值:"+returnValue);
    }
}

配置spring文件中后置配置

定义后置通知

        
            
            
                
                   
                    
                    
                   afterAdvice
                    
                
            
            
            
                
            
 
 
            
            
                    
                        biz.IBookBiz
                    
            
        

初始化spring.xml上下文并执行目标方法

//1.初始化Spring上下文容器(IOC)
ApplicationContext ac=new ClassPathXmlApplicationContext("spring.xml");
IBookBiz proxy = ac.getBean("proxy", IBookBiz.class);
//调用buy和comment方法时,会将前置通知应用到目标方法上得到代理对象
proxy.buy("李四","西游记",200d);
proxy.comment("李四","好看,名著");

 执行结果为


环绕通知(MethodInterceptor)

同上面步骤,只是实现MethodInterceptor接口

public class AroundAdvice implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        //获取目标对象
        Object target = invocation.getThis();
        //获取目标方法的执行参数
        Method method = invocation.getMethod();
        //获取目标方法的执行参数
        Object[] arguments = invocation.getArguments();

        System.out.println("[环绕通知]"+target.getClass().getName()+"."+
                method.getName()+"执行参数:"+ Arrays.toString(arguments));

        //执行目标方法
        Object returnValue = invocation.proceed();

        System.out.println("[环绕通知]"+target.getClass()+"."+
                method.getName()+"执行参数:"+Arrays.toString(arguments)+
                "返回值:"+returnValue);

        return returnValue;
    }
}

异常处理通知(ThrowsAdvice)

创建异常类

public class PriceException extends RuntimeException{
    public PriceException() {
    }

    public PriceException(String message) {
        super(message);
    }

    public PriceException(String message, Throwable cause) {
        super(message, cause);
    }

    public PriceException(Throwable cause) {
        super(cause);
    }

    public PriceException(String message, Throwable cause, boolean enableSuppression,              
                                       boolean writableStackTrace) {
        super(message, cause, enableSuppression, writableStackTrace);
    }
}

创建异常通知类

public class ExceptionAdvice implements ThrowsAdvice {

    public void afterThrowing( PriceException ex ) {
        System.out.println("[异常通知] 买书价格异常,购买失败!");
    }
}

我在实现类中写入了一个判断书本价格书否为空和小于0

public boolean buy(String userName, String bookName, Double price) {
		// 通过控制台的输出方式模拟购书
		if (null == price || price <= 0) {
			throw new PriceException("book price exception");
		}
		System.out.println(userName + " buy " + bookName + ", spend " + price);
		return true;
}

然后定义异常通知Bean

再在目标中使用异常通知Bean

价格为200d

 价格为-200d


适配器(org.springframework.aop.support.RegexpMethodPointcutAdvisor)

适配器=通知+切入点

定义适配器Bena,在这里我用的通知是后置通知

这里的Value的值是方法名       .*方法名

    
        
        
            
        
        
        
        
            
                .*buy
            
        
    

再在代理中加入此适配器

    
        
        
            
                
                
                
                
                regexpmethod
            
        
        
        
            
        
        
        
            
                com.zking.spring02.biz.IBookBiz
            
        
    

执行结果为

李四 buy 西游记, spend 200.0
[适配器]买书返利2元!
李四 say:好看,名著

至此,Spring之AOP介绍完毕,由于作者水平有限难免有疏漏,欢迎留言纠错。

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

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

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