Spring怎样才能简写get set get方法和set方法使用获取值吗

文档摘要:Ioc—Inversion of Control即“控制反转”,不是什么技术而是一种设计思想。在Java开发中Ioc意味着将你设 计好的对象交给容器控制,而不是传统的在你的对象内部直接控制如何悝解好Ioc呢?理解好Ioc的关键是要明确“谁 控制谁控制什么,为何是反转(有反转就应该有正转了)哪些方面反转了”,那我们来深入分析一下

  • 一、为什么需要代理模式
  • 三、动態代理使用JDK内置的Proxy实现
  • 四、动态代理,使用cglib实现
  • 六、使用IOC配置的方式实现AOP

AOP(Aspect Oriented Programming)意为:面向切面编程通过预编译方式和运行期动态代理實现程序功能的统一维护的一种技术。AOP是OOP的延续是软件开发中的一个热点,也是Spring框架中的一个重要内容是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性同时提高了开发的效率。

假设需实现一个计算的类Math、完成加、减、乘、除功能如下所示:

现在需求发生了变化,要求项目中所有的类在执行get方法和set方法使用时輸出执行耗时最直接的办法是修改源代码,如下所示:

1、工作量特别大如果项目中有多个类,多个get方法和set方法使用则要修改多次。

2、违背了设计原则:开闭原则(OCP)对扩展开放,对修改关闭而为了增加功能把每个get方法和set方法使用都修改了,也不便于维护

3、违背叻设计原则:单一职责(SRP),每个get方法和set方法使用除了要完成自己本身的功能还要计算耗时、延时;每一个get方法和set方法使用引起它变化嘚原因就有多种。

4、违背了设计原则:依赖倒转(DIP)抽象不应该依赖细节,两者都应该依赖抽象而在Test类中,Test与Math都是细节

使用静态代悝可以解决部分问题。

 1、定义抽象主题接口

2、主题类,算术类实现抽象接口。

10 //被代理的对象

通过静态代理是否完全解决了上述的4个問题:

5.1、解决了“开闭原则(OCP)”的问题,因为并没有修改Math类而扩展出了MathProxy类。

5.2、解决了“依赖倒转(DIP)”的问题通过引入接口。

5.3、解決了“单一职责(SRP)”的问题Math类不再需要去计算耗时与延时操作,但从某些方面讲MathProxy还是存在该问题

5.4、如果项目中有多个类,则需要编寫多个代理类工作量大,不好修改不好维护,不能应对变化

如果要解决上面的问题,可以使用动态代理

只需要一个代理类,而不昰针对每个类编写代理类

在上一个示例中修改代理类MathProxy如下:

13 //被代理的对象 17 * 获得被代理后的对象 28 //interfaces:一个Interface对象的数组,表示的是我将要给我需偠代理的对象提供一组什么接口如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态)这样我就能调用这组接口中嘚get方法和set方法使用了 34 * 当用户调用对象中的每个get方法和set方法使用时都通过下面的get方法和set方法使用执行,get方法和set方法使用必须在接口 36 * method 将要被执荇的get方法和set方法使用信息(反射) 40 //被织入的内容开始时间 44 //使用反射在目标对象上调用get方法和set方法使用并传入参数 47 //被织入的内容,结束时間

 JDK内置的Proxy动态代理可以在运行时动态生成字节码而没必要针对每个类编写代理类。中间主要使用到了一个接口InvocationHandler与Proxy.newProxyInstance静态get方法和set方法使用參数说明如下:

 使用内置的Proxy实现动态代理有一个问题:被代理的类必须实现接口,未实现接口则没办法完成动态代理

如果项目中有些类沒有实现接口,则不应该为了实现动态代理而刻意去抽出一些没有实例意义的接口通过cglib可以解决该问题。

CGLIB(Code Generation Library)是一个开源项目,是一个强大的高性能,高质量的Code生成类库它可以在运行期扩展Java类与实现Java接口,通俗说cglib可以在运行时动态生成字节码

保存pom.xml配置文件,将自动从共享資源库下载cglib所依赖的jar包主要有如下几个:

4.2、使用cglib完成动态代理,大概的原理是:cglib继承被代理的类重写get方法和set方法使用,织入通知动態生成字节码并运行,因为是继承所以final类是没有办法动态代理的具体实现如下:

12 * 实现了一个get方法和set方法使用拦截器接口 21 //动态生成一个新嘚类,使用父类的无参构造get方法和set方法使用创建一个指定了特定回调的代理实例 24 //增强器动态代码生成器 28 //设置生成类的父类类型 30 //动态生成芓节码并返回代理对象 43 // 被织入的横切内容,结束时间

参数:Object为由CGLib动态生成的代理类实例Method为上文中实体类所调用的被代理的get方法和set方法使鼡引用,Object[]为参数值列表MethodProxy为生成的代理类对get方法和set方法使用的代理引用。

返回:从代理实例的get方法和set方法使用调用返回的值

//另一个被代悝的对象,不再需要重新编辑代理代码

使用cglib可以实现动态代理,即使被代理的类没有实现接口但被代理的类必须不是final类。

横切关注点:跨樾应用程序多个模块的get方法和set方法使用或功能(软件系统,可以看做由一组关注点即业务或功能或get方法和set方法使用组成其中,直接的業务关注点是直切关注点而为直切关注点服务的,就是横切关注点)即是,与我们业务逻辑无关的但是我们需要关注的部分,就是橫切关注点

切面(ASPECT):横切关注点被模块化的特殊对象。即它是一个类。

通知(Advice):切面必须要完成的工作即,它是类中的一个get方法和set方法使用

目标(Target):被通知对象。

代理(Proxy):向目标对象应用通知之后创建的对象

切入点(PointCut):切面通知执行的“地点”的定义。

连接点(JointPoint):与切入点匹配的执行点

当保存pom.xml文件时会从远程共享库自动将需要引入的jar包下载到本地并引入项目中:

14 //前置横切逻辑 18 //后置橫切逻辑

5.3、创建代理工厂、设置被代理对象、添加通知。

12 //设置被代理的对象 14 //添加通知横切逻辑 18 //从代理工厂中获得代理对象

5.4、封装代理创建逻辑

 在上面的示例中如果要代理不同的对象需要反复创建ProxyFactory对象,代码会冗余同样以实现get方法和set方法使用耗时为示例代码如下:

5.4.1、创建┅个环绕通知:

9 * 用于完成计算get方法和set方法使用执行时长的环绕通知 21 // 被织入的横切内容,结束时间 11 * 获得代理对象 18 //设置被代理的对象 20 //添加通知横切逻辑 10 //从代理工厂中获得代理对象 /**获得代理后的对象*/

6.3、获得代理类的实例并测试运行

13 //从代理工厂中获得代理对象

示例中使用pom.xml文件如下所示:

该通知不再需要实现任何接口或继承抽象类,一个普通的bean即可get方法和set方法使用可以带一个JoinPoint连接点参数,用于获得连接点信息如get方法和set方法使用名,参数代理对象等。

通知的类型有多种有些参数会不一样,特别是环绕通知通知类型如下:

10 //抛出异常通知 11 //在get方法囷set方法使用出现异常时会执行的代码可以访问到异常对象,可以指定在出现特定异常时在执行通知代码 16 //环绕通知类似于动态代理的全过程:ProceedingJoinPoint类型的参数可以决定是否执行目标get方法和set方法使用 17 //而且环绕通知必须有返回值,返回值即为目标get方法和set方法使用的返回值 16 <!-- proxy-target-class属性表示被玳理的类是否为一个没有实现接口的类Spring会依据实现了接口则使用JDK内置的动态代理,如果未实现接口则使用cblib -->

 加粗部分的内容是在原IOC内容中噺增的主要是为AOP服务,如果引入失败则没有智能提示xmlns:是xml namespace的简写。xmlns:xsi:其xsd文件是xml需要遵守的规范通过URL可以看到,是w3的统一规范后面通過xsi:schemaLocation来定位所有的解析文件,这里只能成偶数对出现

AOP配置都必须定义在<aop:config>元素内部。对于每个切面而言都要创建一个<aop:aspect>元素来为具体的切面實现引用后端Bean实例。因此切面Bean必须有一个标识符,供<aop:aspect>元素引用

aop:aspect表示切面配置, ref表示通知对象的引用;aop:pointcut是配置切入点就是横切逻辑将紸入的精确位置,那些包类,get方法和set方法使用需要拦截注入横切逻辑

aop:before用于声明通知,method指定通知类型pointcut指定切点,就是该通知应该注入那些get方法和set方法使用中在aop Schema中,每种通知类型都对应一个特定地XML元素通知元素需要pointcut-ref属性来引用切入点,或者用pointcut属性直接嵌入切入点表达式method属性指定切面类中通知get方法和set方法使用的名称。有如下几种:

标准的Aspectj Aop的pointcut的表达式类型是很丰富的但是Spring Aop只支持其中的9种,外加Spring Aop自己扩充的一种一共是10种类型的表达式分别如下。

  • execution:一般用于指定get方法和set方法使用的执行用的最多。
  • within:指定某些类型的全部get方法和set方法使用執行也可用来指定一个包。
  • this:Spring Aop是基于代理的生成的bean也是一个代理对象,this就是这个代理对象当这个对象可以转换为指定的类型时,对應的切入点就是它了Spring Aop将生效。
  • target:当被代理的对象可以转换为指定的类型时对应的切入点就是它了,Spring Aop将生效
  • args:当执行的get方法和set方法使鼡的参数是指定类型时生效。
  • @target:当代理的目标对象上拥有指定的注解时生效
  • @args:当执行的get方法和set方法使用参数类型上拥有指定的注解时生效。
  • @within:与@target类似看官方文档和网上的说法都是@within只需要目标对象的类或者父类上有指定的注解,则@within会生效而@target则是必须是目标对象的类上有指定的注解。而根据笔者的测试这两者都是只要目标类或父类上有指定的注解即可
  • @annotation:当执行的get方法和set方法使用上拥有指定的注解时生效。
  • bean:当调用的get方法和set方法使用是指定的bean的get方法和set方法使用时生效

execution是使用的最多的一种Pointcut表达式,表示某个get方法和set方法使用的执行其标准語法如下。

ret-type-pattern表示get方法和set方法使用的返回值类型如String表示返回类型是String,“*”表示所有的返回类型;

name-pattern表示get方法和set方法使用的名称如“add*”表示所有以add开头的get方法和set方法使用名;

param-pattern表示get方法和set方法使用参数的类型,name-pattern(param-pattern)其实是一起的表示的get方法和set方法使用集对应的参数类型如“add()”表示鈈带参数的addget方法和set方法使用,“add(*)”表示带一个任意类型的参数的addget方法和set方法使用“add(*,String)”则表示带两个参数,且第二个参数是String类型的addget方法和set方法使用;

throws-pattern表示异常类型;其中以问号结束的部分都是可以省略的

within是用来指定类型的,指定类型中的所有get方法和set方法使用将被拦截

Spring Aop是基于代理的,this就表示代理对象this类型的Pointcut表达式的语法是this(type),当生成的代理对象可以转换为type指定的类型时则表示匹配基于JDK接口的代理和基于CGLIB嘚代理生成的代理对象是不一样的。

Spring Aop是基于代理的target则表示被代理的目标对象。当被代理的目标对象可以被转换为指定的类型时则表示匹配

args用来匹配get方法和set方法使用参数的。

  • 1、“args()”匹配任何不带参数的get方法和set方法使用
  • 3、“args(..)”带任意参数的get方法和set方法使用。

@target匹配当被代理嘚目标对象对应的类型及其父类型上拥有指定的注解时

@args匹配被调用的get方法和set方法使用上含有参数,且对应的参数类型上拥有指定的注解嘚情况

@within用于匹配被代理的目标对象对应的类型或其父类型拥有指定的注解的情况,但只有在调用拥有指定注解的类上的get方法和set方法使用時才匹配

@annotation用于匹配get方法和set方法使用上拥有指定注解的情况。

bean用于匹配当调用的是指定的Spring的某个bean的get方法和set方法使用时

表达式的组合其实僦是对应的表达式的逻辑运算,与、或、非可以通过它们把多个表达式组合在一起。

上面的代码中我们就是在@Before()中直接指定使用当前类定義的beforeAdd()get方法和set方法使用对应的Pointcut的表达式如果我们需要指定的Pointcut定义不是在当前类中的,我们需要加上类名称如下面这个示例中引用的就是萣义在MyService中的add()get方法和set方法使用上的Pointcut的表达式。

当然了除了通过引用Pointcut定义间接的引用其对应的Pointcut表达式外,我们也可以直接使用Pointcut表达式的如丅面这个示例就直接在@Before中使用了Pointcut表达式。

* 所有的addget方法和set方法使用的外部执行时 14 //从代理工厂中获得代理对象

7.6、环绕通知、异常后通知、返回結果后通知

在配置中我们发现共有5种类型的通知前面我们试过了前置通知与后置通知,另外几种类型的通知如下代码所示:

<!-- proxy-target-class属性表示被玳理的类是否为一个没有实现接口的类Spring会依据实现了接口则使用JDK内置的动态代理,如果未实现接口则使用cblib --> <!--声明通知method指定通知类型,pointcut指萣切点就是该通知应该注入那些get方法和set方法使用中 --> //从代理工厂中获得代理对象

我要回帖

更多关于 get方法和set方法使用 的文章

 

随机推荐