• 一、静态代理设计模式
    • 1.为什么需要代理设计模式
      • 1.1回顾MVC和三层架构
      • 1.2为什么需要代理
    • 2.代理设计模式
      • 2.1概念
      • 2.2开发的核心要素
      • 2.3实战
      • 2.4静态代理存在的问题
  • 二、动态代理
    • 1.Spring动态代理的概念
    • 2.开发环境
    • 3.Spring动态代理的开发步骤
    • 4.动态代理细节分析
  • 三、Spring动态代理详解
    • 1.MethodBeforeAdvice详解
    • 2.MethodInterceptor(方法拦截器)
    • 3切入点详解
      • 3.1切入点表达式
        • 3.1.1方法切入点表达式
      • 3.2类切入点
      • 3.3包切入点
    • 4.切入点函数
      • 4.1execution,args,within切入点函数
      • 4.2@annotation
      • 4.3切入点函数的逻辑运算
  • 四、AOP
    • 1.AOP概念
    • 2.AOP编程的开发步骤
    • 3.切面的名词解释
    • 4.AOP底层实现原理
      • 1.核心问题
      • 2.JDK动态代理
      • 3.CGlib动态代理

一、静态代理设计模式

1.为什么需要代理设计模式

1.1回顾MVC和三层架构

我们先来回顾一下MVC

MVC:Model 模型 比如实体类 ,View 视图 比如JSP页面,Controller 控制器 比如Servlet
早期的三层架构
用户直接访问控制层,控制层就可以直接操作数据库
servlet–对数据进行增删改查
缺点:程序臃肿,不利于维护
Servlet的代码中:处理请求,响应,视图跳转,处理JDBC,处理业务代码,处理逻辑代码
因为上面的架构,分工不够明确,所以就演变成下面这样的架构

Model:

  • 业务处理:业务逻辑(Service)
  • 数据持久层:CRUD(DAO)

View

  • 展示数据
  • 提供连接发起Servlet请求

Controller

  • 接收用户请求:(req:请求参数,Session参数)
  • 提供连接发起Servlet请求交给业务层处理对应的代码
  • 控制视图跳转
  • 登录—>接收用户登录请求—>处理用户请求(获取用户登录的参数用户名,密码)—>交给业务层处理登录业务(判断用户名密码是否正确)—>DAO层查询用户名和密码是否正确

然后来简单回顾一个开发中的分层
DAO—>Service—>Controler

  • DAO:数据访问层,主要用来对数据库的数据进行操作

  • Service:业务层,用来处理业务逻辑

  • Controler:控制器

这里我推荐两篇关于MVC和三层架构的文章,我个人觉得讲解得很详细
浅谈 MVC与三层架构
MVC与三层架构理解

1.2为什么需要代理

Service层中主要是用来处理业务的,也就是核心功能,像那些业务逻辑,访问数据库的操作等。像那些事务,日志,性能等操作,属于附加功能,可有可无,代码量也比较少
那么额外功能写在Service层中好不好呢

  • Service层从调用者角度(Controller):需要在Service层写额外功能
  • 从软件设计角度,不希望Service层写额外功能,因为它是可有可无的

接下来举一个现实生活中的例子来说明一下生活中也会有类似场景

比如说有人想要租房子,那么我们可以把房东看成一个类,代表业务类,包含核心功能也就是和房客签订出租房屋的合同,但是它肯定不能只有核心功能,别人为什么要找你租房,而不是找其他人呢?可能是因为你张贴广告,并且房客来看过房子了,所以还需要有额外功能,贴广告和看房。但是我们来想一下,贴广告这些其实挺累的,房东肯定不想做这些事情,他们希望的是房客直接来找他们签合同租房,也就是不希望额外功能。但是房客又不允许房东没有额外功能,毕竟没有看到房子怎么样,房客怎么可能直接签订合同

  • 房东(类似于软件设计者):不想要额外功能
  • 房客(调用者):想要额外功能

我们肯定是尽量满足所有人的要求的,所以我们以后就跟房东说,你只要实现核心功能就可以了,其他的不用你管。但是房客就很迷糊了,我都不知道谁有房子出租,而且没有看房怎么签合同。这个时候,中介(Proxy)出现了,中介说,大家放心,我负责提供房子信息,房客以后就只需要找中介就可以了,房客看到房子后觉得很满意,想要签订合同,但是这个时候,这个功能就不属于中介管了,这就需要房东了,毕竟房产证又不在你中介手里,房客说,我怎么知道这个房子是你的,万一不是你的,我的钱不就打水漂了,所以到签合同的这个时候,中介就会说,房东你来吧,这样子房客的诉求也满足了,皆大欢喜了。
如果说,房客对中介提供的房源不满意,那么他可以找其他的中介,这样子,我们发现,我们并不需要修改代码,这样就提高了代码的维护性

2.代理设计模式

2.1概念

  • 通过代理类,为原始类(目标类)增加额外功能
  • 代理类提供的方法要和目标类的方法一一对应
  • 有利于目标类的维护
  • 目标类(原始类):指的是业务类,里面只做核心功能,比如业务运算,DAO的调用
  • 目标方法(原始方法):目标类中的方法
  • 额外功能:比如事务,日志,性能

2.2开发的核心要素

代理类=目标类+额外功能+目标类和代理类要实现相同的接口(为了让代理类和目标类的方法保持同步)

2.3实战

我们以租房子为例,来进行演示,下面这个演示是静态代理
静态代理:为每一个目标类,都提供一个代理类
提供代理类和目标类的公共接口

public interface House {/*** 出租房屋*/public void rent();}

房东

/**房东* @author zengyihong* @create 2022--04--18 22:13*/
public class Landlord implements House {@Overridepublic void rent() {System.out.println("房东:签订合同,出租房屋");}
}

房屋中介(代理类)

**房屋中介* @author zengyihong* @create 2022--04--18 22:12*/
public class HouseProxy implements House {Landlord landlord=new Landlord();Lodger lodger=new Lodger();/*** 当中介带领房客看房屋后,如果房客说满意,那么就可以签订合同了* 如果房客不满意,那么他可能就会寻找其他房屋了*/@Overridepublic void rent() {boolean flag= lodger.satisfy();;if (flag){landlord.rent();}else {System.out.println("房客:我还想看看其他的房屋");}}/*** 带领想租房子的人看房,对方如果说满意了,就可以签订合同了* @return*/public void show(){System.out.println("中介:带领房客看房屋");rent();}
}

房客

/**房客* @author zengyihong* @create 2022--04--18 22:11*/
public class Lodger {Scanner scanner=new Scanner(System.in);/*** 看房子是否满意*/public boolean satisfy(){System.out.println("请问您对房子满意吗(Y/N)");String str=scanner.next();if ("Y".equalsIgnoreCase(str)){return true;}else{return false;}}}

测试

2.4静态代理存在的问题

  • 静态代理的类文件过多,一个目标类就有一个代理类,不利于项目管理
  • 以上面的代码举例子,可能有不同的中介来提供房屋信息,不同的中介其实它们提供的功能基本是一样的,但是现在写了这么多的代理类,其实也没什么意义
  • 额外功能维护性差,也就是代理类中,额外功能修改复杂,比较麻烦

二、动态代理

1.Spring动态代理的概念

动态代理和静态代理在概念上没有什么区别,主要是开发步骤和底层实现的不同

  • 概念:通过代理类为目标类增加额外功能
  • 好处:有利于目标类的维护

2.开发环境

<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>org.example</groupId><artifactId>spring-01</artifactId><version>1.0-SNAPSHOT</version><name>spring-01</name><!-- FIXME change it to the project's website --><url>http://www.example.com</url><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><maven.compiler.source>1.7</maven.compiler.source><maven.compiler.target>1.7</maven.compiler.target></properties><dependencies><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.11</version><scope>test</scope></dependency><dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter</artifactId><version>RELEASE</version><scope>compile</scope></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.3.18</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.3.18</version></dependency>
<!--    日志--><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId><version>1.7.21</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>1.7.21</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.16</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-aop</artifactId><version>5.3.18</version></dependency><!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver --><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.6</version><scope>runtime</scope></dependency><!-- https://mvnrepository.com/artifact/org.aspectj/aspectjrt --><dependency><groupId>org.aspectj</groupId><artifactId>aspectjrt</artifactId><version>1.9.8</version><scope>runtime</scope></dependency></dependencies></project>

3.Spring动态代理的开发步骤

public interface UserService {public void register(User user);public boolean login(String name,String password);
}

①创建原始对象(目标对象)

/*** 原始类** @author zengyihong* @create 2022--04--18 21:57*/
public class UserServiceImpl implements UserService {@Overridepublic void register(User user) {System.out.println("UserServiceImpl.register 业务运算+DAO");}@Overridepublic boolean login(String name, String password) {System.out.println("UserServiceImpl.login");return true;}
}

然后在Spring的配置文件进行配置来创建对象

<bean id="userServiceImpl" class="com.zyh.proxy.UserServiceImpl"></bean>

②提供额外功能
我们需要把额外功能写在MethodBeforeAdvice接口的实现中
一旦实现了这个接口,那么在运行的时候,这个接口里面的额外功能会在原始类的方法运行前执行

/**before方法的作用就是把运行在原始方法执行之前运行的额外功能写在before方法中* @author zengyihong* @create 2022--04--19 8:56*/
public class Before implements MethodBeforeAdvice {@Overridepublic void before(Method method, Object[] args, Object target) throws Throwable {System.out.println("----method before advice log---");}
}
 <bean id="before" class="com.zyh.dynamic.Before"></bean>

③定义切入点

  • 切入点指的是额外功能加入的位置
  • 目的:由程序员根据自己的需要,觉得额外功能加给哪一个原始方法
  • 简单测试:所有方法都作为切入点,都加入额外的功能
<!--代表所有方法都作为切入点 目前是login register--><aop:config><aop:pointcut id="pc" expression="execution(* *(..))"/></aop:config>

④组装
把第二步和第三步进行整合
为了看清楚一点,我把上面的配置都在这里体现

  <bean id="userServiceImpl" class="com.zyh.proxy.UserServiceImpl"></bean>
<!--代表所有方法都作为切入点 目前是login register--><aop:config><aop:pointcut id="pc" expression="execution(* *(..))"/>
<!--        组装,把切入点和额外功能整合--><aop:advisor advice-ref="before" pointcut-ref="pc"></aop:advisor></aop:config>

⑤调用
获得Spring工厂创建的动态代理对象,并且进行调用

ApplicationContext ctx=new ClassPathXmlApplicationContext("/applicationContext.xml");
注意:
1.Spring工厂通过原始对象的id值获得的是代理对象
2.获得代理对象后,可以通过声明接口类型,进行对象的存储
UserService userService=(UserService)ctx.getBean("userServiceImpl");
userService.login("","");
userService.regist();

测试

 @Testpublic void test() {ApplicationContext ctx = new ClassPathXmlApplicationContext("/applicationContext3.xml");UserService userService = (UserService) ctx.getBean("userServiceImpl");userService.login("tom","123");userService.register(new User());}

运行结果

----method before advice log---   额外功能
UserServiceImpl.login              原始功能
----method before advice log---
UserServiceImpl.register 业务运算+DAO

4.动态代理细节分析

  • Spring创建的动态代理类在哪里?

    • Spring创建的动态代理类,是Spring框架在运行的时候,通过动态字节码技术,在JVM创建的,运行在JVM内部,等程序结束后,会和JVM一起消失
  • 什么又叫动态字节码技术

    • 先来回顾一下,以前是怎么运行一个类,是JVM运行这个类的字节码文件,然后创建该对象,进而调用这个对象的方法
    • 现在通过动态字节码技术的话,我们就不需要编写源文件编译成.class文件
    • 动态字节码是通过第三方框架来完成,我们通过这些框架,就可以直接在JVM生成字节码(动态字节码),把动态字节码加载到JVM中后,就可以创建对象了
    • 动态代理其实就是动态字节码

    总结一下

    • 动态字节码技术:通过第三方的动态字节码框架,在JVM中创建对应类的字节码,进而创建对象
    • 动态代理不需要定义类文件,都是JVM运行过程中动态创建的,所以不会产生像静态代理,类文件数量过多,影响项目管理的问题
  • 动态代理编程简化代理的开发

    • 在额外功能不变的情况下,我们在创建目标类的代理对象时,只需要指定目标对象就可以了
  • 动态代理额外功能的维护性大大增强

    • 以前用静态代理的话,比如说有几个类的方法的功能是一样的,但是这个时候我们想要修改它的功能,就得对这几个类的方法都进行修改,比较麻烦
    • 使用动态代理的话,我们只需要新创建一个类来实现 MethodBeforeAdvice接口,并且实现里面的before方法,然后在配置文件进行配置即可

三、Spring动态代理详解

1.MethodBeforeAdvice详解

 @Overridepublic void before(Method method, Object[] args, Object target) throws Throwable {System.out.println("----method before advice log---");}
  • Method:指的是额外功能要增加给的那个原始方法

    • 比如是在login方法执行之前,我们想要执行这个额外功能,那么login就是原始方法
    • 额外功能要增加给的原始方法的参数

MethodBeforeAdvice接口作用:额外功能运行在原始方法执行前进行额外功能操作的话,就得实现这个接口

2.MethodInterceptor(方法拦截器)

我们要写一个类实现这个接口,并且实现这个接口的invoke方法

  @Overridepublic Object invoke(MethodInvocation invocation) throws Throwable {return null;}

可以在原始方法执行之前或之后运行
所以我们应该要先知道原始方法在什么时候运行,这样才可以让额外功能在原始方法之前或之后运行
MethodInvocation invocation:这个参数代表的就是额外功能所增加给的那个原始方法

这个方法就代表原始方法的执行invocation.proceed();

方法的返回值Object代表原始方法的返回值,如果原始方法没有返回值,就认为返回的是null

配置文件配置

<bean id="arround" class="com.zyh.dynamic.Arround"></bean><!--代表所有方法都作为切入点 目前是login register--><aop:config><aop:pointcut id="pc" expression="execution(* *(..))"/>
<!--        组装,把切入点和额外功能整合--><aop:advisor advice-ref="arround" pointcut-ref="pc"></aop:advisor></aop:config>
public class Arround implements MethodInterceptor {/*** 我们把额外功能写在invoke方法中,这样额外功能就可以运行在原始方法执行之前或之后* @param invocation* @return* @throws Throwable*/@Overridepublic Object invoke(MethodInvocation invocation) throws Throwable {System.out.println("额外功能执行");Object obj = invocation.proceed();return obj;}
}

运行效果

像事务的开启,提交这样的操作,我们就可以把它写在核心功能的前面和后面,在前面写事务的开启,在后面写事务的提交
额外功能如果是运行在原始方法抛出异常的时候呢,我们可以在try-catch里面写额外功能

3切入点详解

切入点决定了额外功能添加的位置

<!--代表所有方法都作为切入点 目前是login register--><aop:config><aop:pointcut id="pc" expression="execution(* *(..))"/>
<!--        组装,把切入点和额外功能整合--><aop:advisor advice-ref="arround" pointcut-ref="pc"></aop:advisor></aop:config>
execution(* *(..))匹配了所有方法
execution是切入点函数* *(..)是切入点表达式

3.1切入点表达式

3.1.1方法切入点表达式

 * *(..)是切入点表达式 匹配了所有方法


接下来我们来看看,怎么把一个具体的方法定义成切入点

  • 定义login方法作为切入点
<!--代表所有方法都作为切入点 目前是login register--><aop:config><aop:pointcut id="pc" expression="execution(* login(..))"/>
<!--        组装,把切入点和额外功能整合--><aop:advisor advice-ref="arround" pointcut-ref="pc"></aop:advisor></aop:config>

  • 定义login方法并且login方法有两个字符串类型的参数作为切入点
 <aop:config><aop:pointcut id="pc" expression="execution(* login(String,String ))"/>
<!--        组装,把切入点和额外功能整合--><aop:advisor advice-ref="arround" pointcut-ref="pc"></aop:advisor></aop:config>

如果我们说切入点的参数类型和我们的方法类型不匹配,就不会执行额外功能
注意:如果参数类型不是java.lang包中的类型,在切入点中必须写全限定名称

上面讲解的方法切入点表达式不精准,因为不同的包可能有同名同参的方法,我们本来只是想要匹配其中的一个方法,但是现在就会导致匹配多个方法。
为了解决这个方法,我们就得通过包,类,方法名,参数来限定我们要选择的方法
切入点

<!--代表所有方法都作为切入点 目前是login register--><aop:config><aop:pointcut id="pc" expression="execution(* com.zyh.proxy.UserServiceImpl.login())"/>
<!--        组装,把切入点和额外功能整合--><aop:advisor advice-ref="arround" pointcut-ref="pc"></aop:advisor></aop:config>

3.2类切入点

如果一个类的所有方法都要加入额外功能的话,我们就可以把整个类作为切入点,这样就避免一个方法一个方法来配置了

  <aop:config><aop:pointcut id="pc" expression="execution(* com.zyh.proxy.UserServiceImpl.*(..))"/>
<!--        组装,把切入点和额外功能整合--><aop:advisor advice-ref="arround" pointcut-ref="pc"></aop:advisor></aop:config>


注意:*只能套一层包,比如说类A写在com.zyh.proxy下面,那么这个时候,如果我们写的是*.UserServiceImpl.(…)是不可以的,因为*只能处理一层包
但是如果我们这个时候就想用*的话,要怎么办
那就写* . .UserServiceImpl.
(…)注意:这里有两个.
两个.代表一级包乃至多级包

3.3包切入点

包切入点就是说把指定包作为额外功能加入的位置,那么,包的所有类以及方法都会加入额外功能

      <aop:pointcut id="pc" expression="execution(* com.zyh.proxy.*.*(..))"/>

注意:如果使用这种方法的话,那么切入点包中的所有类必须放在proxy包下面,而不能是proxy包下的子包
如果我们想要把proxy包及其子包下的所有类及其方法作为切入点的话,要怎么办?

 <aop:pointcut id="pc" expression="execution(* com.zyh.proxy..*.*(..))"/>

注意:com.zyh.proxy. . *.*(…)
proy后面有两个.代表proxy包及其子包

4.切入点函数

4.1execution,args,within切入点函数

切入点函数:用于执行切入点表达式
接下来看看有哪些主要的切入点函数
①execution
execution函数是最重要的切入点函数,功能最全面
它可以执行方法切入点表达式,类切入点表达式,包切入点表达式
缺点:execution执行切入点表达式书写麻烦
为了书写简单一点,因此就有其他切入点函数,它们的功能是一样的,只是为简化execution的复杂度
②args
主要用来方法参数的匹配
比如说方法是什么我们现在并不关心,只关心参数类型,这个时候就可以使用这个
execution(* (String ,String))
args(String,String)


③within
主要用于类,包切入点表达式的匹配
比如说我们选择切入点是UserServiceImpl,不关心它是哪一个包的
execution(* *. .UserServiceImpl.*
(String ,String))
within(*. .UserServiceImpl)
如果是要把某一包及其子包下面的类和方法作为切入点
within(com.zyh.proxy. .*)

4.2@annotation

作用:为具有特殊注解的方法加入额外功能
我们以后可能为某一个方法来加入注解,那么这个时候,@annotaion就会进行扫描,如果扫描到某个注解,就可以为它进行切入
所以第一步我们要先自定义一个注解



4.3切入点函数的逻辑运算

切入点函数的逻辑运算指的是:整合多个切入点函数一起配合工作,进而完成更为复杂的需求
①and与操作

案例:login方法 同时参数是两个字符串
execution(* login(String,String))
execution(* login(..)) and args(String,String)

注意:与操作不能用于同种类型的切入点函数

②or或操作

execution(* login(..)) or execution(* register(..))

四、AOP

1.AOP概念

AOP(Aspect Oriented Programing):面向切面编程
面向切面编程就是以切面为基本单位的程序开发,通过切面间的彼此协同相互调用,完成程序的构建
切面=切入点+额外功能

  • AOP的概念

    • 本质上是Spring的动态代理开发,通过代理类为原始类增加额外功能
    • 好处:有利于原始类的维护

2.AOP编程的开发步骤

①原始对象
②额外功能
③切入点
私组装切面(额外功能+切入点)

3.切面的名词解释

4.AOP底层实现原理

1.核心问题

①AOP怎么创建动态代理类(动态字节码技术)
②Spring工厂怎么加工创建代理对象
通过原始对象的id值,获得的是代理对象

2.JDK动态代理


package com.zyh.jdk;import com.zyh.proxy.User;
import com.zyh.proxy.UserService;
import com.zyh.proxy.UserServiceImpl;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;/*** @author zengyihong* @create 2022--04--20 16:34*/
public class TestJDKProxy {public static void main(String[] args) {//创建原始对象final UserService userService=new UserServiceImpl();//JDK动态代理/*** InvocationHandler:提供额外功能  额外功能其实是一个接口*/InvocationHandler handler=new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("---proxy  log-----");//原始方法运行Object obj = method.invoke(userService, args);return obj;}};UserService userServiceProxy= (UserService)Proxy.newProxyInstance(TestJDKProxy.class.getClassLoader(),userService.getClass().getInterfaces(),handler);userServiceProxy.login("tom","123");userServiceProxy.register(new User());}
}
---proxy  log-----
UserServiceImpl.login
---proxy  log-----
UserServiceImpl.register 业务运算+DAO

3.CGlib动态代理

CGlib创建动态代理的原理:父子继承关系创建代理对象,原始类作为辅助,代理类作为子类,既可以保证二者方法一致,同时还可以在代理类中提供新的方法实现(额外功能+原始方法)

public class UserService {public void login(String name,String password){System.out.println("UserService.login");}public void register(User user){System.out.println("UserService.register");}}
public class TestCglib {public static void main(String[] args) {//创建原始对象final UserService userService = new UserService();//CGlib方式创建动态代理对象Enhancer enhancer = new Enhancer();enhancer.setClassLoader(TestCglib.class.getClassLoader());enhancer.setSuperclass(userService.getClass());MethodInterceptor interceptor = new MethodInterceptor() {@Overridepublic Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {System.out.println("-------cglib  log---------");Object obj = method.invoke(userService, args);return obj;}};enhancer.setCallback(interceptor);UserService userServiceProxy = (UserService) enhancer.create();userServiceProxy.login("tom","123");userServiceProxy.register(new User());}
}

JDK动态代理 Proxy.newProxyInstance()   通过接口插件代理的实现类
Cglib动态代理 Enhancer    通过继承父类创建的代理类

Spring ----AOP相关推荐

  1. Spring AOP + Redis解决重复提交的问题

    Spring AOP + Redis解决重复提交的问题 用户在点击操作的时候,可能会连续点击多次,虽然前端可以通过设置按钮的disable的属性来控制按钮不可连续点击,但是如果别人拿到请求进行模拟,依 ...

  2. 利用Spring AOP与JAVA注解为系统增加日志功能

    Spring AOP一直是Spring的一个比较有特色的功能,利用它可以在现有的代码的任何地方,嵌入我们所想的逻辑功能,并且不需要改变我们现有的代码结构. 鉴于此,现在的系统已经完成了所有的功能的开发 ...

  3. Spring AOP的一些概念

            切面(Aspect): 一个关注点的模块化,这个关注点可能会横切多个对象.事务管理是J2EE应用中一个关于横切关注点的很好的例子. 在Spring AOP中,切面可以使用通用类(基于模 ...

  4. Spring AOP与IOC

    Spring AOP实现日志服务 pom.xml需要的jar <dependency><groupId>org.apache.commons</groupId>&l ...

  5. Spring AOP与IOC以及自定义注解

    Spring AOP实现日志服务 pom.xml需要的jar <dependency><groupId>org.apache.commons</groupId>&l ...

  6. Spring Aop的应用

    2019独角兽企业重金招聘Python工程师标准>>> AOP的基本概念 连接点( Jointpoint) : 表示需要在程序中插入横切关注点的扩展点,连接点可能是类初始化.方法执行 ...

  7. Spring AOP详解(转载)所需要的包

    上一篇文章中,<Spring Aop详解(转载)>里的代码都可以运行,只是包比较多,中间缺少了几个相应的包,根据报错,几经百度搜索,终于补全了所有包. 截图如下: 在主测试类里面,有人怀疑 ...

  8. 关于spring aop Advisor排序问题

    关于spring aop Advisor排序问题 当我们使用多个Advisor的时候有时候需要排序,这时候可以用注解org.springframework.core.annotation.Order或 ...

  9. 利用spring aop统一处理异常和打日志

    利用spring aop统一处理异常和打日志 spring aop的概念,很早就写博客介绍了,现在在工作中真正使用. 我们很容易写出的代码 我们很容易写出带有很多try catch 和 logger. ...

  10. 我所理解的Spring AOP的基本概念

    Spring AOP中的概念晦涩难懂,读官方文档更是像读天书,看了很多例子后,写一些自己理解的一些spring的概念.要理解面向切面编程,要首先理解代理模式和动态代理模式. 假设一个OA系统中的一个功 ...

最新文章

  1. 怎么彻底删除电脑上的软件_你的电脑有救了:1 个神器几个进阶方法彻底删除流氓软件!...
  2. CPSR和SPSR(转)
  3. 从单体到混乱的微服务,阿里云托管式服务网格是如何诞生的?
  4. vue中使用Ueditor编辑器 -- 1
  5. leetcode面试题 16.19. 水域大小(深度优先搜索)
  6. python pandas库 画图_python绘图:matplotlib和pandas的应用
  7. html内容封装为一个对象_技术赋能还是内容为王,哪一个才是短视频创作的关键?...
  8. mysql约束类型 A P_mysql笔记: 数据类型、约束、范式
  9. 反汇编基础-加法的求值过程(各种类型)
  10. Feature Layer with selection(ArcGIS JS Api 图上点选)
  11. 地铁人多不多可在线查询了 高德地图率先在北京上线新功能
  12. cocos creator入门教程(十八)—— creator_Director对象与资源加载策略
  13. 论文笔记:Bridging Textual and Tabular Data for Cross-Domain Text-to-SQL Semantic Parsing
  14. 建立ad-hoc网络 // 电脑设置wifi热点 (Win10)
  15. js 实现图片放大镜原理
  16. Pytorch框架学习记录10——线性层
  17. win7(32bit)下完整的搭建apache(2.2.x)+openssl(0.9.6-1.0.1升级)过程
  18. tiny4412移植uboot-2019-01(三)
  19. 奔跑吧,我的JavaScript(1)
  20. 排线颜色及排序视觉检测系统

热门文章

  1. Oracle内核技术揭密
  2. kafka源码分析之副本管理-ReplicaManager
  3. 二维码,如何设计创意二维码
  4. ps基础学习:利用选框和填充工具做图标
  5. 秘密显示技术:戴上眼镜才能看到你的内容
  6. Qt学习(四)条件编译
  7. ABAP项目砖家之旅-ABAP对象命名规则
  8. 尚硅谷微信支付详细步骤全部打通
  9. 浏览器打印不弹出预览直接打印
  10. 文件夹加密软件推荐-文件夹加密超级大师