spring中的aop 是怎么面向切面编程的 从头认识Spring-1.2 什么是AOP?为什么需要面向切...

spring \u6846\u67b6\u7684\u9762\u5411\u5207\u9762\u7f16\u7a0b\u5982\u4f55\u7406\u89e3\uff1f

Spring\u63d0\u4f9b\u4e86\u5bf9AOP\u6280\u672f\u7684\u826f\u597d\u5c01\u88c5\uff0cAOP\u79f0\u4e3a\u9762\u5411\u5207\u9762\u7f16\u7a0b\uff0c\u5c31\u662f\u7cfb\u7edf\u4e2d\u6709\u5f88\u591a\u5404\u4e0d\u76f8\u5e72\u7684\u7c7b\u7684\u65b9\u6cd5\uff0c\u5728\u8fd9\u4e9b\u4f17\u591a\u7684\u65b9\u6cd5\u4e2d\u8981\u52a0\u5165\u67d0\u79cd\u7cfb\u7edf\u529f\u80fd\u4ee3\u7801\uff0c\u4f8b\u5982\uff1a\u52a0\u5165\u65e5\u5fd7\u3001\u6743\u9650\u5224\u65ad\u3001\u5f02\u5e38\u5904\u7406\u7b49\uff0c\u8fd9\u79cd\u5e94\u7528\u6210\u4e3aAOP\u3002
\u5b9e\u73b0AOP\u529f\u80fd\u91c7\u7528\u7684\u662f\u4ee3\u7406\u6280\u672f\uff0c\u5ba2\u6237\u7aef\u7a0b\u5e8f\u4e0d\u518d\u8c03\u7528\u76ee\u6807\uff0c\u800c\u8c03\u7528\u4ee3\u7406\u7c7b\uff0c\u4ee3\u7406\u7c7b\u4e0e\u76ee\u6807\u7c7b\u5bf9\u5916\u5177\u6709\u76f8\u540c\u7684\u65b9\u6cd5\u58f0\u660e\uff0c\u6709\u4e24\u79cd\u65b9\u5f0f\u53ef\u4ee5\u5b9e\u73b0\u76f8\u540c\u7684\u65b9\u6cd5\u58f0\u660e\uff0c\u4e00\u662f\u5b9e\u73b0\u76f8\u540c\u7684\u63a5\u53e3\uff0c\u800c\u662f\u4f5c\u4e3a\u76ee\u6807\u7684\u5b50\u7c7b\u5728JDK\u4e2d\u91c7\u7528Proxy\u7c7b\u4ea7\u751f\u52a8\u6001\u4ee3\u7406\u7684\u65b9\u5f0f\u4e3a\u67d0\u4e2a\u63a5\u53e3\u751f\u6210\u5b9e\u73b0\u7c7b\uff0c\u5982\u679c\u8981\u4e3a\u67d0\u7c7b\u4e2a\u751f\u6210\u5b50\u7c7b\uff0c\u5219\u53ef\u4ee5\u7528CGLIB\u3002
\u5728\u751f\u6210\u7684\u4ee3\u7406\u7c7b\u7684\u65b9\u6cd5\u4e2d\u52a0\u5165\u7cfb\u7edf\u529f\u80fd\u548c\u8c03\u7528\u76ee\u6807\u7c7b\u7684\u76f8\u5e94\u65b9\u6cd5\uff0c\u7cfb\u7edf\u529f\u80fd\u7684\u4ee3\u7406\u4ee5Advice\u5bf9\u8c61\u8fdb\u884c\u63d0\u4f9b\uff0c\u663e\u7136\u8981\u521b\u5efa\u51fa\u4ee3\u7406\u5bf9\u8c61\uff0c\u81f3\u5c11\u9700\u8981\u76ee\u6807\u7c7b\u548cAdvice\u7c7b\u3002
Sping\u63d0\u4f9b\u4e86\u8fd9\u79cd\u652f\u6301\uff0c\u53ea\u9700\u8981\u5728Sping\u914d\u7f6e\u6587\u4ef6\u4e2d\u914d\u7f6e\u8fd9\u4e24\u4e2a\u5143\u7d20\u5373\u53ef\u5b9e\u73b0\u4ee3\u7406\u548cAop\u529f\u80fd\uff0c
\u4f8b\u5982\uff1a





\u9762\u5411\u5207\u9762\u53d8\u6210\u80fd\u591f\u5f88\u5927\u7a0b\u5ea6\u4e0a\u8f83\u5c11\u4ee3\u7801\u91cf\uff0c\u5e76\u4e14\u53ef\u4ee5\u6df1\u5165\u5230\u65b9\u6cd5\u5185\u90e8\uff0c\u52a8\u6001\u7ed9\u65b9\u6cd5\u6dfb\u52a0\u529f\u80fd\uff0c\u6bd4\u5982\u589e\u52a0\u65e5\u5fd7\u7684\u529f\u80fd\uff0c\u8bbe\u7f6e\u524d\u7f6e\u529f\u80fd\uff0c\u540e\u7f6e\u8865\u5145\u529f\u80fd\u3002Aop\u7528\u5230\u9762\u5411\u5bf9\u8c61\u7684\u7f16\u7a0b\u4e2d\uff0c\u7b80\u76f4\u5c31\u662f\u5982\u864e\u6dfb\u7ffc\u3002\u8fd9\u4e48\u65b9\u4fbf\u7684\u4e1c\u897f\u4e3a\u4ec0\u4e48\u4e0d\u4f7f\u7528\u5462\uff1f
\u4e3e\u4e2a\u4f8b\u5b50\uff0c\u4f60\u8981\u7ed9\u4e00\u4e2a\u65b9\u6cd5\uff0c\u6dfb\u52a0\u52a8\u6001\u6dfb\u52a0\u6bb5\u529f\u80fd\uff0c\u6bd4\u5982\u8bf4\u505a\u524d\u7f6e\u6821\u9a8c\uff1a
public void test(){ //code}\u5982\u679c\u4f60\u91c7\u7528\u4f20\u7edf\u65b9\u6cd5\uff0c\u53ef\u80fd\u9700\u8981\u501f\u52a9\u52a8\u6001\u4ee3\u7406\u6765\u751f\u6210\u4e00\u4e2a\u4ee3\u7406\u7c7b\uff0c\u901a\u8fc7\u4ee3\u7406\u5bf9\u8c61\u7684invoke()\u65b9\u6cd5\u5229\u7528\u53cd\u5c04\u539f\u7406\u7ed9\u65b9\u6cd5\u6dfb\u52a0\u529f\u80fd\uff0c\u4f46\u662f\u8fd9\u6837\u505a\u7684\u8bdd\uff0c\u4f1a\u5f88\u9ebb\u70e6\uff0c\u5e76\u4e14\u5f88\u5bb9\u6613\u51fa\u9519\u3002\u501f\u52a9\u4e8eAop\uff0c\u5c31\u53ef\u4ee5\u76f4\u63a5\u5b9a\u4e49\u4e00\u4e2a\u5207\u9762\uff0c\u7136\u540e\u58f0\u660e\u4e00\u4e2a\u5207\u70b9\uff0c\u7ed9\u65b9\u6cd5\u52a8\u6001\u6dfb\u52a0\u4e86\u529f\u80fd\uff0c\u5e76\u4e14\u4e0d\u5177\u6709\u4fb5\u5165\u6027\u3002

Spring面向切面编程(AOP)

1 spring容器中bean特性


Spring容器的javabean对象默认是单例的。


通过在xml文件中,配置可以使用某些对象为多列。


Spring容器中的javabean对象默认是立即加载(立即实例化:spring加载完成,立即创建对象)


scope:属性


singleton:默认值为单例,默认也是立即加载,在加载完成spring容器的时候,bean对象已经创建完成   


prototype:多例的,默认懒加载,spring容器加载完成的时候,不会创建bean的对象,只有从容器获得bean对象的时候,才进行bean对象的实例化


request: 将创建的javabean对象,封装到request范围


session:将创建的javabean对象,封装到session范围


Spring容器bean的对象生命周期:


Bean对象的创建一直到销毁为bean的生命周期。


生命周期的开始:


如果为单例,由加载完spring容器开始


如果为多例,由从容器获得bean对象开始


实例化


初始化


服务


销毁(单例:关闭容器的时候,多例由jvm自动回收)


2 spring的AOP面向切面编程


2.1 模拟银行转账业务


需求:实现银行的转账功能,在转账的时候需要完成


1 身份认证(登陆)


2 权限的验证


3 转账实现


4 历史交易记录,


分析:1,2,4三个功能对于银行的业务,属于公共的功能(共性的功能)


在功能实现的时候,需要将1,2,4抽取出来,单独实现,


做到了将共性的功能和核心的业务功能进行了分离


通过动态代理实现:共性的功能和核心业务功能的合并,产生核心业务对象的


在代码实现的时候,进行了功能实现的分离:


代码开发的进行分离,程序在运行的时候进行合并。


2.2 springAOP的思想


在系统开发中,将系统的共性的公共的功能独立实现,在程序运行的过程中,将共性功能和核心的业务功能,进行整合。


好处:


1 完成共性功能和核心业务功能的解耦合


2 提供共性功能的复用性。


2.3springAOP的概念 


Aspect切面:封装共性功能的(增强功能的)类


Advice通过:切面类中封装的增强功能的方法。


PointCut:切入点,是一个集合的概念,该集合的表达使用一个正则表达式表达


所有核心业务对象的所有方法的前后(事务处理AOP典型的应用)


JoinPoint:连接点,程序中需要加入advice的地方,而且正在执行的ponitCut


织入(Weaving):将aspect和核心业务对象,进行整合的过程。


3 springAOP的实现


3.1通过特定接口实现


Aop通知的类型:


Before:前置通知


After:后置通知


Around:环绕通知


Throwing:异常通知


需求:实现在业务对象中的方法执行的时候,记录日志功能


3.1.1前置通知

package org.guangsoft.utils;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Date;
import org.springframework.aop.MethodBeforeAdvice;
/****
 * 前置增强:
 * MethodBeforeAdvice 接口表示重写的方法为前置advice
 * ***/
public class BeforeLog implements MethodBeforeAdvice
{
    @Override
    public void before(Method method,
    Object[] args, Object obj)
    throws Throwable
    {
        System.out.println(method);
        System.out.println(Arrays.toString(args));
        System.out.println(obj);
        System.out.println("BeforeLog-------------" + new Date());
    }
}


AOP配置:

<?xml version="1.0" encoding="UTF-8"?>
<!-- 到入xml文件的约束 -->
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:aop="http://www.springframework.org/schema/aop" xmlns:p="http://www.springframework.org/schema/p"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
     http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
     http://www.springframework.org/schema/aop
     http://www.springframework.org/schema/aop/spring-aop-4.1.xsd">
    <!-- 实例化BeforeLog对象 -->
    <bean id="bf" class="org.guangsoft.utils.BeforeLog"></bean>
    <!-- 实例化service对象 -->
    <bean id="us" class="org.guangsoft.service.impl.UsersServiceImpl" />
    <!-- 进行aop的配置,产生代理对象 -->
    <aop:config>
        <!-- 声明切入点 -->
        <aop:pointcut expression="execution(* org.guansoft.service.impl.*.*(..))"
            id="pc" />
        <!-- 织入 将通知和切入点进行合并(切面+核心业务对象) -->
        <aop:advisor advice-ref="bf" pointcut-ref="pc" />
    </aop:config>
</beans>


3.1.2后置通知


对业务对象的方法进行后增强。

package org.guangsoft.utils;
import java.lang.reflect.Method;
import java.util.Date;
import org.springframework.aop.AfterReturningAdvice;
/***
 * 后置通知
 * ***/
public class AfterLog implements AfterReturningAdvice
{
    @Override
    public void afterReturning(Object obj1,// obj1 接收目标方法的返回值
            Method method,
            Object[] args,
            Object obj2) throws Throwable
    {
        // System.out.println(obj1+"----------------------"+obj2);
        System.out.println("AfterLog-------------------" + new Date());
    }
}


AOP配置:

<?xml version="1.0" encoding="UTF-8"?>
<!-- 到入xml文件的约束 -->
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:aop="http://www.springframework.org/schema/aop" xmlns:p="http://www.springframework.org/schema/p"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
     http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
     http://www.springframework.org/schema/aop
     http://www.springframework.org/schema/aop/spring-aop-4.1.xsd">
    <!-- 实例化BeforeLog对象 -->
    <bean id="bf" class="org.guangsoft.utils.BeforeLog"></bean>
    <bean id="af" class="org.guangsoft.utils.AfterLog"></bean>
    <!-- 实例化service对象 -->
    <bean id="us" class="org.guangsoft.service.impl.UsersServiceImpl" />
    <!-- 进行aop的配置,产生代理对象 -->
    <aop:config>
        <!-- 声明切入点 -->
        <aop:pointcut expression="execution(* org.guangsoft.service.impl.*.*(..))"
            id="pc" />
        <!-- 织入 将通知和切入点进行合并(切面+核心业务对象) -->
        <aop:advisor advice-ref="bf" pointcut-ref="pc" />
        <aop:advisor advice-ref="af" pointcut-ref="pc" />
    </aop:config>
</beans>


3.1.3环绕通知

package org.guangsoft.utils;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Date;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
/***
 * 环绕通知
 * ***/
public class AoundLog implements MethodInterceptor
{
    /**
     * MethodInvocation中封装了目标对象,调用的方法,方法需要的参数
     * ***/
    @Override
    public Object invoke(MethodInvocation mi) throws Throwable
    {
        Method method = mi.getMethod();
        Object[] args = mi.getArguments();
        Object obj = mi.getThis();
        System.out.println(method);
        System.out.println(Arrays.toString(args));
        System.out.println(obj);
        System.out.println("around------before--------" + new Date());
        Object rv = method.invoke(obj, args);// 调用目标对象的方法,放行
        System.out.println("around------after--------" + new Date());
        return rv;
    }
}


AOP配置:同上


3.1.4 异常通知

package org.guangsoft.utils;
import java.util.Date;
import org.springframework.aop.ThrowsAdvice;
/****
 * 异常通知
 * **/
public class ExceptionLog implements ThrowsAdvice
{
    /***
     * 该类中的方法参考AfterReturningAdvice写
     * 该参数是用来接收异常信息的
     * ***/
    public void afterThrowing(Throwable ex) throws Throwable
    {
        // System.out.println(obj1+"----------------------"+obj2);
        System.out.println("ExceptionLog-----------" + ex.getMessage()
                + "--------" + new Date());
    }
}

Pointcut:核心业务对象

Advice:通知



建议看看反射机制

扩展阅读:spring aop 实现原理 ... spring aop理解 ... springer官网入口 ... spring aop实现过程 ... spring aop ioc ... spring aop实现方式 ... spring aop实例讲解 ... spring aop例子 ... spring aop失效 ...

本站交流只代表网友个人观点,与本站立场无关
欢迎反馈与建议,请联系电邮
2024© 车视网