增加Spring系列笔记

This commit is contained in:
fxb 2018-08-05 21:39:32 +08:00
parent bae774343a
commit 5a8c9a66b2
5 changed files with 632 additions and 0 deletions

170
spring/1.spring基础.md Normal file
View File

@ -0,0 +1,170 @@
  spring是为了解决企业级应用开发的复杂性而创建的spring最根本的使命是简化Java开发。为降低开发复杂性有以下四种关键策略。
- 基于POJO的轻量级和最小侵入性编程
- 通过依赖注入和面向接口实现松耦合
- 基于切面和惯例进行声明式编程
- 通过切面和模板减少样板式代码
#### 1.依赖注入
  假设类A依赖类B通常做法是在类A中声明类B然后使用这样一方面具有极高的耦合性将类A与类B绑定在一起另一方面也让单元测试变得很困难无法在A外部获得B的执行情况。
  通过依赖注入,对象的依赖管理将不用对象本身来管理,将由一个第三方组件在创建对象时设定,依赖关系将被自动注入到对应的对象中去。
#### 2.创建应用上下文
- `ClassPathXmlApplicationContext()`从类路径创建
- `FileSystemXmlApplicationContext()`读取文件系统下的xml配置
- `XmlWebApplicationContext()` 读取web应用下的XML配置文件并装载上下文定义
#### 3.声明Bean
1. 最简单
`<bean id="bean1" class="com.example.Class"/>`
2. 带构造器
```xml
<bean id="bean1" class="com.example.Class">
<contructor-arg value="12"/> //基本数据类型使用value
<contructor-arg ref="bean2"/> //对象使用ref
</bean>
```
3. 通过工厂方法创建
如果想声明的Bean没有一个公开的构造函数通过factory-method属性来装配工厂生产的Bean
```xml
<bean id="bean1" class="com.example.class" factory-method="getInstance"/>//getInstance为获取实例的静态方法。
```
#### 4.Bean的作用域
所有Spring Bean默认都是单例的。通过配置scope属性为prototype可每次请求产生一个新的实例。
```xml
<bean id="bean3" class="com.example.class" scope="prototype">
```
scope可选值
- `singleton`每个容器中一个Bean对象只有一个实例。**默认**
- `prototype`:允许实例化任意次 ,每次请求都会创建新的
- `request`作用域为一次http请求
- `session`作用域为一个http session会话
- `global-session`作用域为一个全局http session仅在Protlet上下文中有效
#### 5.初始化和销毁Bean
当实例化需要执行初始化操作,或者销毁时需要执行清理工作。两种实现方式:
1. xml配置类中编写初始化方法和销毁方法在bean中定义。
```xml
<bean id="bean4" class="com.example.Class" init-method="start" destroy-method="destroy"/>
```
也可在Beans中定义默认初始化和销毁方法。
```xml
<beans . . . default-init-method="" default-destroy-method=""/>
```
2. 实现`InitializingBean ``DisposableBean`接口
#### 6.setter注入
在bean中使用`<property>`元素配置属性,使用方法类似于`<constructor-arg>`
```xml
<property name="name" value="fxg"/> //注入基本数据类型
<property name="sex" ref="sex"/> //注入类
```
可使用p简写,**-ref**后缀说明装配的是一个引用
```xml
<bean id="bean5" class="com.example.class"
p:name="fxb"
p:sex-ref="sex"/>
```
#### 7.注入内部Bean
既定义其他Bean内部的Bean避免共享问题可在属性节点或者构造器参数节点上使用。
```xml
<property name="sex">
<bean class="com.example.sex"/> //没有id属性因为不会被其他bean使用
</property>
<constructor-arg>
<bean class="com.example.sex"/>
</constructor-arg>
```
#### 8.装配集合
| 集合元素 | 用途 |
| ---------------- | ------------------------------ |
| \<list\> | 装配list类型允许重复 |
| \<set\> | set不能重复 |
| \<map\> | map类型 |
| \<props\> | properties类型键值都为String |
- list
```xml
<property name="instruments">
<list>
<ref bean="guitar"/>
<ref bean="cymbal"/>
<ref bean="harmonica"/>
</list>
</property>
<ref>用来定义上下文中的其他引用,还可使用<value>,<bean>,<null/>
```
- set
```xml
<set>
<ref bean="fasdf"/>
</set>
```
用法和list相同只是不能重复
- Map
```XML
<map>
<entry key="GUITAR" value-ref="guitar"/>
</map>
```
entry元素由一个key一个value组成分别有两种形式。
| key | 键为String |
| :-------- | -------------- |
| key-ref | 键为Bean的引用 |
| value | 值为String |
| value-ref | 值为Bean的引用 |
- props
```xml
<props>
<prop key="GUITAR">guitar</prop>
</props>
```
键值都是String
#### 9.装配空值
```xml
<property name="name"><null/></property>
```

View File

@ -0,0 +1,223 @@
## 一、自动装配
### 1、四种类型的自动装配
| 类型 | 解释 | xml配置 |
| ---------- | ------------------------------------ | ---------------------------------------------- |
| byName | 根据Bean的name或者id | \<bean id="bean" class="…" autowire="byName"/> |
| ByType | 根据Bean类型自动装配 | \<bean id="bean" class="…" autowire="byType"/> |
| contructor | 根据Bean的构造器入参具有相同类型 | 同上 |
| Autodetect | 首先使用contructor失败再尝试byType | 同上 |
&emsp;&emsp;byType在出现多个匹配项时不会自动选择一个然是报错为避免报错有两种办法1.使用\<bean>元素的primary属性设置为首选Bean但所有bean的默认primary都是true因此我们需要将所有非首选Bean设置为false2.将Bean的`autowire-candidate`熟悉设置为**false **,取消 这个Bean的候选资格这个Bean便不会自动注入了。
&emsp;&emsp;contructor自动装配和byType有一样的局限性当发现多个Bean匹配某个构造器入参时Spring不会尝试选择其中一个此外如果一个类有多个构造器都满足自动装配的条件Spring也不会猜测哪个更合适使用。
###2、默认自动装配
&emsp;&emsp;如果需要为Spring应用上下文中的每个Bean或者其中的大多数配置相同的autowire属性可以在根元素\<beans>上增加一个default-autowire属性默认该属性设置为none。该属性只应用于指定配置文件中的所有Bean并不是Spring上下文中的所有Bean。
###3、混合使用自动装配和显式装配
&emsp;&emsp;当我们对某个Bean使用了自动装配策略并不代表我们不能对该Bean的某些属性进行显示装配任然可以为任意一个属性配置\<property>元素,显式装配将会覆盖自动装配。**但是**当使用constructor自动装配策略时我们必须让Spring自动装配构造器所有入参不能使用\<constructor-arg>元素进行混合。
## 二、注解装配
&emsp;&emsp;从Spring2.5开始可以使用注解自动装配Bean的属性使用注解允许更细粒度的自动装配可选择性的标注某一个属性来对其应用自动装配。Spring容器默认禁用注解装配需要在Spring配置中启用最简单的启用方式是使用Spring的context命令空间配置中的`<context:annotation-config>`,如下所示:
```xml
<beans ...>
<context:annotation-config/>
<!-- bean declarations go here -->
</beans>
```
&emsp;&emsp;Spring3支持几种不同的用于自动装配的注解
- Spring自带的@Autowired注解
- JSR-330的@Inject注解
- JSR-250的@Resource注解
###1、使用@Autowired
&emsp;&emsp;@Autowired用于对被注解对象启动ByType的自动装配,可用于以下对象:
- 类属性,即使私有属性也能注入
- set方法
- 构造器
- 任意需要装配Bean的方法
在使用@Autowired时有两种情况会出错没有匹配的Bean和存在多个匹配的Bean但是都有对应的解决方法。
- 当没有匹配Bean时自动装配会抛出NoSuchBeanDefinitionException如果不想抛出可使用required属性设置为false来配置可选的自动装配即装配失败就不进行装配不会报错。
```java
@Autowired(required=false)
```
当使用构造器配置时只有一个构造器可以将required属性设置为true其他都只能设置为false。此外当使用注解标注多个构造器时Spring会从所有满足装配条件的构造器中选择入参最多的那个。
- 当存在多个Bean满足装配条件时Spring也会抛出NoSuchBeanDefinitionException错误为了选择指定的Bean我们可以使用@Qualifier注解进行筛选:
```java
@Autowired
@Qualifier("name1")//筛选名为name1的Bean
private TestClass testClass;
```
除了通过Bean的ID来缩小选择范围我们还可以通过直接在Bean上使用qualifier来缩小范围限制Bean的类型xml如下
```xml
<bean class="com.test.xxx">
<qualifier value="stringed"/>
</bean>
```
注解如下:
```java
@Qualifier("stringed")
public class xxx{}
```
还可以创建**自定义限定器Qualifier**
&emsp;&emsp;创建自定义限定器只需要使用@Qualifier注解作为它的源注解即可如下创建了一个Stringed限定器
```java
@Target({ElementType.FIELD,ElementType.PARAMETER,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface Stringed{}
```
然后使用它注解一个Bean:
```java
@Stringed
public class Guitar{}
```
然后就可以进行限定了:
```java
@Autowired
@Stringed
private Guitar guitar;
```
### 2、使用@Inject自动注入
&emsp;&emsp;为统一各种依赖注入框架的编程模型JCPJava Community Process发布的Java依赖注入规范被称为JSR-330从Spring3开始Spring已经开始兼容该依赖注入模型。
&emsp;&emsp;@Autowired一样@Inject可以用来自动装配属性、方法和构造器。但是@Inject没有required属性,因此依赖关系必须存在,如不存在将抛出异常。
&emsp;&emsp;JSR-330还提供另一种注入技巧注入一个Provider。Provider接口可以实现Bean引用的延迟注入以及注入Bean的多个实例等功能。
&emsp;&emsp;例如我们有一个KnifeJuggler类需要注入一个或多个Knife实例假设Knife Bean的作用域声明为prototype下面的KnifeJuggler的构造器将获得多个Knife Bean:
```java
private Set<Knife> knifes;
@Inject
public KnifeJuggler(Provider<Knife> knifeProvider){
knives = new HashSet<Knife>();
for(int i=0;i<5;i++){
knives.add(knifeProvider.get());
}
}
```
&emsp;&emsp;相对于@Autowired所对应的@Qualifier@Inject对应的是@Named注解。事实上JSR-330中也有@Qualifier注解不过不建议直接使用建议通过该注解来创建自定义的限定注解和Spring的@Qualifier创建过程类似
### 3、注解中使用表达式
&emsp;&emsp;Spring3中引入的`@Value`属性可用来装配String类型的值和基本类型的值。借助SpEL表达式@Value不光可以装配硬编码值还可以在运行期动态计算表达式并装配,例如下面的:
```java
@Value("#{systemProperties.name}")
private String name;
```
## 三、自动检测Bean
&emsp;&emsp;在Spring中使用上面说到的`<context:annotation-config>`可以做到自动装配但还是要在xml中申明Bean。Spring还有另一个元素`<context:component-scan>`,元素除了完成自动装配的功能还允许Spring自动检测Bean和定义Bean ,用法如下:
```xml
<beans ...>
<context:component-scan base-package="com.springtest">
</context:component-scan>
</beans>
```
开启后支持如下注解:
| 注解 | 解释 |
| ----------- | ------------------------------------ |
| @Component | 通用的构造型注解标识类为Spring组件 |
| @Controller | 标识该类定义为Spring MVC controller |
| @Repository | 标识该类定义为数据仓库 |
| @Service | 标识该类定义为服务 |
&emsp;&emsp;使用上述注解是Bean的ID默认为无限定类名。使用`@Component("name")`指定ID。
### 1、过滤组建扫描
&emsp;&emsp;通过为<context:component-scan >配置<context:include-filter ><context:exclude-filter >子元素我们可以随意调整扫描行为。下面的配置自动注册所有的TestInterface实现类
```xml
<context:component-scan base-package="com.fxb.springtest">
<context:include-filter type="assignable"
expression="com.fxb.springTest.TestInterface"/>
</context:component-scan>
```
其中的type和expression属性一起协作来定义组件扫描策略。type有以下值可选择
| 过滤器类型 | 描述 |
| ---------- | ------------------------------------------------------------ |
| annotation | 过滤器扫描使用指定注解所标注的类。通过expression属性指定要扫描的注解 |
| assignable | 过滤器扫描派生于expression属性所指定类型的那些类 |
| aspectj | 过滤器扫描于expression属性所指定的AspectJ表达式所匹配的那些类 |
| custom | 使用自定义的org.springframework.core.type.TypeFilter实现类该类由expression属性指定 |
| regex | 过滤器扫描类的名称与expression属性所指定的正则表达式所匹配的类 |
&emsp;&emsp;exclude-filter使用和include-filter类似只是效果相反。
## 四、使用Spring基于Java的配置
&emsp;&emsp;在Spring3.0中几乎可以不使用XML而使用纯粹的Java代码来配置Spring应用。
- 首先还是需要极少量的XML来启用Java配置就是上面说到的`<context:component-scan>`,该标签还会自动加载使用`@Configuration`注解所标识的类
- @Configuration注解相当于XML配置中的\<beans>元素这个注解将会告知Spring这个类包含一个或多个Spring Bean的定义这些定义是使用@Bean注解所标注的方法
- 申明一个简单的Bean代码如下
```java
@Configuration
public class TestConfig{
@Bean
public Animal duck(){
return new Ducker();
}
}
```
@Bean告知Spring这个方法将返回一个对象该对象应该被注册为Spring应用上下文中的一个Bean方法名作为该Bean的ID 。想要使用另一个Bean的引用也很简单如下
```java
@Bean
public Food duckFood(){
return new DuckFood();
}
@Bean //通过方法名引用一个Bean并不会创建一个新的实例
public Animal duck(){
return new Ducker(DuckFood());
}
```
## 五、小结
&emsp;&emsp;终于写完了spring 的最小化配置对spring的各种注解也有了一些了解再不是之前看到注解一脸莫名其妙了虽然现在Springboot已经帮我们做了零XML配置但觉得还是有必要了解下XML配置实现这样对Java的配置实现理解也会更加深刻。

View File

@ -0,0 +1,239 @@
## 一.面向切面编程
&emsp;&emsp;Spring的基础是IOC和AOP前面两节对IOC和DI做了简单总结这里再对AOP进行一个学习总结Spring基础就算有一个初步了解了。
&emsp;&emsp;在软件开发中,我们可能需要一些跟业务无关但是又必须做的东西,比如日志,事务等,这些分布于应用中多处的功能被称为横切关注点,通常横切关注点从概念上是与应用的业务逻辑相分离的。如何将这些横切关注点与业务逻辑在代码层面进行分离,是面向切面编程(**AOP**)所要解决的。
横切关注点可以被描述为影响应用多处的功能,切面能够帮助我们模块化横切关注点。下图直观呈现了横切关注点的概念:
![横切关注点](./3.面向切面的Spring/切面示例.png)
途中CourseServiceStudentServiceMiscService都需要类似安全、事务这样的辅助功能这些辅助功能就被称为横切关注点。
&emsp;&emsp;**继承**和**委托**是最常见的实现重用通用功能的面向对象技术。但是如果在整个程序中使用相同的基类继承往往会导致一个脆弱的对象体系;而使用委托可能需要对委托对象进行复杂的调用。
切面提供了取代继承和委托的另一种选择,而且更加清晰简洁。在面向切面编程时,我们任然在一个地方定义通用功能,但是我们可以通过声明的方式定义这个功能以何种方式在何处应用,而无需修改受影响的类,受影响类完全感受不到切面的存在。
## 二.AOP常用术语
&emsp;&emsp;下面是AOP中常用的名词。
### 1. 通知Advice
&emsp;&emsp;通知定义了切面是什么以及何时使用。出了描述切面要完成的工作通知还解决了何时执行这个工作的问题。Sping切面可以应用以下5种类型的通知。
- **Before** 在方法被调用之前调用通知
- **After** 在方法完成之后调用通知,无论方法执行是否成功
- **After-returning** 在方法成功执行后调用通知
- **After-throwing** 在方法抛出异常后调用通知
- **Around** 通知包裹了被通知的方法,在被通知的方法调用前和调用后执行
###2.连接点Joinpoint
&emsp;&emsp;应用可能有很多个时机应用通知,这些时机被称为连接点。连接点是应用在执行过程中能够插入切面的一个点,这个点可以是调用方法时、抛出异常时、甚至是修改字段时。切面代码可以利用这些切入到应用的正常流程中,并添加新的行为。
### 3.切点Pointcut
&emsp;&emsp;切点定义了通知所要织入的一个或多个连接点。如果说通知定义了切面的“**什么**”和“**何时**”,那么切点就定义了“**何处**”。通常使用明确的类和方法名称来指定切点或者利用正则表达式定义匹配的类和方法来指定这些切点。有些AOP框架允许我们创建动态的切点可以更具运行时的策略来决定是否应用通知。
### 4.切面Aspect
&emsp;&emsp;切面是通知和切点的结合。通知和切点定义了关于切面的全部内容,**是什么**,在**何时**、**何处**完成其功能。
### 5.引入
&emsp;&emsp;引入允许我们想现有的类添加新方法或属性。即在无需修改现有类的情况下让它们具有新的行为和状态。
### 6.织入
&emsp;&emsp;织入是将切面应用到目标对象来创建新的代理对象的过程。切面在指定的连接点被织入到目标对象中,在目标对象的生命周期里有多个点可以进行织入。
- 编译期切面在目标类编译时被织入。这种方式需要特殊的编译期比如AspectJ的织入编译期
- 类加载期切面在目标类加载到JVM时被织入。这种方式需要特殊的加载器它可以在目标类被引入应用之前增强该目标类的字节码例如AspectJ5的**LTW**load-time weaving
- 运行期切面在应用运行的某个时刻被织入。一般情况下AOP容器会为目标对象动态创建一个代理对象
##三.Spring AOP
&emsp;&emsp;Spring在运行期通知对象通过在代理类中包裹切面Spring在运行期将切面织入到Spring管理的Bean中。代理类封装了目标类并拦截被通知的方法的调用再将调用转发给真正的目标Bean。由于Spring是基于动态代理所有Spring只支持方法连接点如果需要方法拦截之外的连接点拦截我们可以利用Aspect来协助SpringAOP。
&emsp;&emsp;Spring在运行期通知对象通过在代理类中包裹切面Spring在运行期将切面织入到Spring管理的Bean中。代理类封装了目标类并拦截被通知的方法的调用再将调用转发给真正的目标Bean。由于Spring是基于动态代理所有Spring只支持方法连接点如果需要方法拦截之外的连接点拦截我们可以利用Aspect来协助SpringAOP。
### 1、定义切点
&emsp;&emsp;在SpringAOP中需要使用AspectJ的切点表达式语言来定义切点。Spring只支持AspectJ的部分切点指示器如下表所示
| AspectJ指示器 | 描述 |
| ------------- | ------------------------------------------------------------ |
| arg() | 限制连接点匹配参数为指定类型的执行方法 |
| @args() | 限制连接点匹配参数由指定注解标注的执行方法 |
| execution() | 用于匹配是连接点的执行方法 |
| this() | 限制连接点匹配AOP代理的Bean引用为指导类型的类 |
| target() | 限制连接点匹配目标对象为指定类型的类 |
| @target() | 限制连接点匹配特定的执行对象,这些对象对应的类要具备指定类型的注解 |
| within() | 限制连接点匹配指定的类型 |
| @within() | 限制连接点匹配指定注解所标注的类型当使用SpringAOP时方法定义在由指定的注解所标注的类里 |
| @annotation | 限制匹配带有指定注解连接点 |
| bean() | 使用Bean ID或Bean名称作为参数来限制切点只匹配特定的Bean |
&emsp;其中只有execution指示器是唯一的执行匹配其他都是限制匹配。因此execution指示器是
其中只有execution指示器是唯一的执行匹配其他都是限制匹配。因此execution指示器是我们在编写切点定义时最主要使用的指示器。
### 2、编写切点
&emsp;&emsp;假设我们要使用execution()指示器选择Hello类的sayHello()方法,表达式如下:
```java
execution(* com.test.Hello.sayHello(..))
```
方法表达式以*** **号开始,说明不管方法返回值的类型。然后指定全限定类名和方法名。对于方法参数列表,我们使用(**标识切点选择任意的sayHello()方法,无论方法入参是什么。
&emsp;&emsp;同时我们可以使用&&(and)||(or)(not)来连接指示器,如下所示:
```java
execution(* com.test.Hello.sayHello(..)) and !bean(xiaobu)
```
### 3、申明切面
&emsp;&emsp;在经典Spring AOP中使用ProxyFactoryBean非常复杂因此提供了申明式切面的选择在Spring的AOP配置命名空间中有如下配置元素
| AOP配置元素 | 描述 |
| ------------------------------ | ----------------------------------------------------------- |
| &lt;aop:advisor &gt; | 定义AOP通知器 |
| &lt;aop:after &gt; | 定义AOP后置通知无论被通知方法是否执行成功 |
| &lt;aop:after-returning &gt; | 定义AOP after-returning通知 |
| &lt;aop:after-throwing &gt; | 定义after-throwing |
| &lt;aop:around &gt; | 定义AOP环绕通知 |
| &lt;aop:aspect &gt; | 定义切面 |
| &lt;aop:aspectj-autoproxy &gt; | 启用@AspectJ注解驱动的切面 |
| &lt;aop:before &gt; | 定义AOP前置通知 |
| &lt;aop:config &gt; | 顶层的AOP配置元素。大多数的&lt;aop:* &gt;元素必须包含在其中 |
| &lt;aop:declare-parents &gt; | 为被通知的对象引入额外的接口,并透明的实现 |
| &lt;aop:pointcut &gt; | 定义切点 |
### 4、实现
假设有一个演员类`Actor`,演员类中有一个表演方法`perform()`,然后还有一个观众类`Audience`,这两个类都在包`com.example.springtest`Audience类主要方法如下
```java
public class Audience{
//搬凳子
public void takeSeats(){}
//欢呼
public void applaud(){}
//计时环绕通知需要一个ProceedingJoinPoint参数
public void timing(ProceedingJoinPoint joinPoint){
joinPoint.proceed();
}
//演砸了
public void demandRefund(){}
//测试带参数
public void dealString(String word){}
}
```
#### a、xml配置实现
&emsp;&emsp;首先将Audience配置到springIOC中:
```xml
<bean id="audience" class="com.example.springtest.Audience"/>
```
然后申明通知:
```xml
<aop:config>
<aop:aspect ref="audience">
<!-- 申明切点 -->
<aop:pointcut id="performance" expression="execution(* com.example.springtest.Performer.perform(..))"/>
<!-- 声明传递参数切点 -->
<aop:pointcut id="performanceStr" expression="execution(* com.example.springtest.Performer.performArg(String) and args(word))"/>
<!-- 前置通知 -->
<aop:before pointcut-ref="performance" method="takeSeats"/>
<!-- 执行成功通知 -->
<aop:after-returning pointcout-ref="performance" method="applaud"/>
<!-- 执行异常通知 -->
<aop:after-throwing pointcut-ref="performance" method="demandRefund"/>
<!-- 环绕通知 -->
<aop:around pointcut-ref="performance" method="timing"/>
<!-- 传递参数 -->
<aop:before pointcut-ref="performanceStr" arg-names="word" method="dealString"/>
</aop:aspect>
</aop:config>
```
#### b、注解实现
直接在Audience类上加注解Aspect注解并不能被spring自动发现并注册要么写到xml中要么使用@Aspectj注解或者加一个@Component注解),如下所示:
```java
@Aspect
public class Audience{
//定义切点
@Pointcut(execution(* com.example.springtest.Performer.perform(..)))
public void perform(){}
//定义带参数切点
@Pointcut(execution(* com.example.springtest.Performer.performArg(String) and args(word)))
public void performStr(String word){}
//搬凳子
@Before("perform()")
public void takeSeats(){}
//欢呼
@AfterReturning("perform()")
public void applaud(){}
//计时环绕通知需要一个ProceedingJoinPoint参数
@Around("perform()")
public void timing(ProceedingJoinPoint joinPoint){
joinPoint.proceed();
}
//演砸了
@AfterThrowing("perform()")
public void demandRefund(){}
//带参数
@Before("performStr(word)")
public void dealString(String word){}
}
```
#### c、通过切面引入新功能
&emsp;&emsp;既然可以用AOP为对象拥有的方法添加新功能那为什么不能为对象增加新的方法呢利用被称为**引入**的AOP概念切面可以为Spring Bean添加新的方法示例图如下
![引入](.\3.面向切面的Spring\引入新功能.png)
当引入接口的方法被调用时代理将此调用委托给实现了新接口的某个其他对象。实际上Bean的实现被拆分到了多个类。
- xml引入需要使用&lt;aop:declare-parents &gt;元素:
```xml
<aop:aspect>
<aop:declare-parents types-matching="com.fxb.springtest.Performer+"
implement-interface="com.fxb.springtest.AddTestInterface"
default-impl="com.fxb.springtest.AddTestImpl"/>
</aop:aspect>
```
顾名思义\&lt;declare-parents&gt;声明了此切面所通知的Bean在它的对象层次结构中有了新的父类型。其中types-matching指定增强的类implement-interface指定实现新方法的接口default-imple指定实现了implement-interface接口的实现类也可以用delegate-ref来指定一个Bean的引用。
- 注解引入,通过`@DeclareParents`注解
```xml
@DeclareParents(value="com.fxb.springtest.Performer+",
defaultImpl=AddTestImpl.class)
public static AddTestInterface addTestInterface;
```
同xml实现一样注解也由三部分组成1、value属性相当于tpes-matching属性标识被增强的类2、defaultImpl等同于default-imple指定接口的实现类3、有@DeclareParents注解所标注的static属性指定了将被引入的接口

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB