SpringIOC&AOP
2021-10-29 11:36:08 0 举报
spring ioc aop
作者其他创作
大纲/内容
Spring的设计理念和整体架构
通过IoC容器来管理POJO对象以及他们相互之间的耦合关系
通过AOP以动态和非侵入式的方式来增强服务的功能
非侵入性框架
Spring提供了一个一致的编程模型,应用直接使用POJO开发
Spring推动应用的设计风格面向对象及面向接口编程转变,提高了代码的重用性和可测试性
Spring改进了体系结构的选择,降低了平台锁定的风险
IoC容器的实现
IoC容器概述
控制反转
当对象被创建时,由一个调控系统内的所有对象的外界实体将其依赖的对象的引用传递给它,即依赖被注入到对象中。
控制反转是关于一个对象如何获取它所依赖的对象的引用,反转指的是责任的反转
依赖注入方式
接口注入
setter注入
构造器注入
IoC容器的设计与实现
接口BeanFactory
接口HierarchicalBeanFactory
接口ApplicationContext
容器的高级形态增加了许多面向框架的特性,同时对应用环境作了许多适配
继承了MessageSource接口
信息源的扩展功能可以支持国际化的实现,为开发多语言版本的应用提供服务
继承了ApplicationEventPublisher接口
在上下文中引入了事件机制,事件和Bean的生命周期结合为Bean的管理提供了便利
接口ConfigurableApplicationContext
抽象类AbstractApplicationContext
抽象类AbstractRefreshableApplicationContext
抽象类AbstractRefreshableConfigApplicationContext
抽象类AbstractXmlApplicationContext
类FileSystemXmlApplicationContext
还有核心子子类ClassPathXmlApplicationContext
接口ConfigurableBeanFactory
通过方法addBeanPostProcessor配置Bean后置处理器
父子级联Ioc容器的接口,子容器可以通过接口方法访问父容器
接口ListableBeanFactory
接口ApplicationContext
接口WebApplicationContext
接口ConfigurableApplicationContext
接口ConfigurableListableBeanFactory
实现类DefaultListableBeanFactory
子类XmlBeanFactory
组合了类XmlBeanDefinitionReader
方法loadBeanDefinitions将Bean信息从Resource载入到BeanDefinitions
方法containsBean
方法getBean
方法getType
方法isSingleton
方法isPrototype
方法getAliases
接口BeanDefinition
依赖反转模式中管理对象依赖关系的数据抽象
用于管理各种对象以及它们之间的相互依赖关系
Ioc容器的接口设计图
IoC容器的初始化过程
Resource定位
由ResourceLoader通过统一的Resource接口来完成
BeanDefinition的载入
BeanDefinitionReader对资源进行信息处理
向IoC容器注册BeanDefinition
通过BeanDefinitionRegistry接口实现
IoC容器的依赖注入
容器其他相关特性的设计与实现
Bean配置方式
基于xml文件的配置-spring1.0支持
基于注解的配置-spring2.0支持
基于Java类的配置-spring3.0支持
基于Groovy动态语言的配置-spring4.0支持
依赖注入方式
基于属性注入
基于构造函数注入
还支持工厂方法注入
FactoryBean
一种Bean创建的一种方式,对Bean的一种扩展。对于复杂的Bean对象初始化创建使用其可封装对象的创建细节。
AOP的实现
Spring AOP概述
概念:面向切面编程Aspect-方面 Oriented-朝向 Programming
通知:接口Advice
前置通知,接口BeforeAdvice
接口MethodBeforeAdvice
待增加的目标方法设置的前置增强接口
回调方法before
返回通知,接口AfterAdvice
接口AfterReturningAdvice
待增加的目标方法设置的后置增强接口
回调方法afterReturning
异常通知,接口ThrowsAdvice
为切面增强提供织入接口
Spring切面可以应用5中类型的通知
前置通知 Before-在目标方法被调用之前调用通知功能
后置通知After-在目标方法完成之后调用通知,此时不会关心方法的输出是什么
返回通知After-returning-在目标方法成功执行之后调用通知
异常通知After-throwing-在目标方法抛出异常后调用通知
环绕通知Around-通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定义的行为
切点:接口Pointcut
决定Advice通知应该作用于哪个连接点,定义需要增强的方法的集合
可以由某个正则表达式进行标识、可以根据某个方法名进行匹配
通知器:接口Advisor
定义应该使用哪个通知并在哪个关注点使用它,把Advice和Pointcut结合起来
接口PointcutAdvisor
抽象类AbstractPointcutAdvisor
抽象类AbstractGenericPointcutAdvisor
实现类DefaultPointcutAdvisor
有两个属性advice和pointcut
Spring AOP的设计与实现
以JDK动态代理技术为基础,设计一系列AOP横切实现,如前置通知、返回通知、异常通知等
集成了AspectJ
AOP流程:需要为目标对象通过动态代理建立代理对象;启动代理对象的拦截器来完成各种横切面的织入,通过一系列Adapter实现织入;
AopProxy代理对象
配置ProxyFactoryBean
定义使用的通知器Advisor,通知器的实现定义了需要对目标对象进行增强的切面行为,也就是Advice通知
定义ProxyFactoryBean中的属性
属性interfaces
被代理接口
属性interceptorNames
需要定义的通知器Advisor
属性targetName
需要增强的目标
接口AopProxy方法getProxy
JdkDynamicAopProxy#getProxy
JDK动态代理生成代理对象
动态代理
Proxy.newProxyInstance参数一
类加载器
Proxy.newProxyInstance参数二
被代理的接口
Proxy.newProxyInstance参数三
Proxy回调方法所在的对象,实现了InvocationHandler的invoke方法
得到链List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);-责任链模式
通过ReflectiveMethodInvocation.process方法进行递归调用
CglibAopProxy#getProxy
Cglib动态代理生成代理对象
依赖AspectJ静态代理
依赖asm字节码技术(同等级的还有javassist)
动态代理
组装Enhancer对象配置生成代理对象,其中callback回调的设置等同于jdk的invoke回调方法,通过CGLIB方式生成代理对象,需要通过DynamicAdvisedInterceptor内部类来完成回调
得到链List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
通过ReflectiveMethodInvocation.process方法进行递归调用
动态代理方式选择通过DefaultAopProxyFactory的createAopProxy方法确定
Spring AOP拦截器调用的实现
设计原理
通过JDK的Proxy方式生成代理对象需要通过InvocationHandler来设置拦截器回调
通过CGLIB方式生成代理对象需要通过DynamicAdvisedInterceptor来完成回调
配置通知器
拦截器链通过缓存加快访问速度AdvisedSupport#getInterceptorsAndDynamicInterceptionAdvice
Advice通知的实现-适配器模式
接口AdvisorAdapter
实现类MethodBeforeAdviceAdapter
方法getInterceptor得到MethodBeforeAdviceInterceptor
实现了MethodInterceptor,BeforeAdvice接口
组合了MethodBeforeAdvice类
实现类AfterReturningAdviceAdapter
方法getInterceptor得到AfterReturningAdviceInterceptor
实现了MethodInterceptor, AfterAdvice接口
组合了AfterReturningAdvice类
实现类ThrowsAdviceAdapter
方法getInterceptor得到ThrowsAdviceInterceptor
实现了MethodInterceptor, AfterAdvice接口
注册器DefaultAdvisorAdapterRegistry
ProxyFactory实现AOP
除使用ProxyFactoryBean实现AOP应用之外,还可使用ProxyFactory来实现Spring AOP的功能,ProxyFactory需要编程式完成AOP应用的设置
ProxyFactory类的父类的父类AdvisedSupport提供相关配置的支持
JDK动态代理和CGLIB动态代理
区别
JDK动态代理只能对实现了接口的类生成代理,而不能针对类
CGLib是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法(继承)
Spring在选择用JDK还是CGLib的依据
当Bean实现接口时,Spring就会用JDK的动态代理
当Bean没有实现接口时,Spring使用CGLib来实现
可以强制使用CGLib(在Spring配置中加入<aop:aspectj-autoproxy proxy-target-class=“true”/>)
JDK和CGLib的性能对比
使用CGLib实现动态代理,CGLib底层采用ASM字节码生成框架,使用字节码技术生成代理类,在JDK1.6之前比使用Java反射效率要高。唯一需要注意的是,CGLib不能对声明为final的方法进行代理,因为CGLib原理是动态生成被代理类的子类。
在JDK1.6、JDK1.7、JDK1.8逐步对JDK动态代理优化之后,在调用次数较少的情况下,JDK代理效率高于CGLib代理效率,只有当进行大量调用的时候,JDK1.6和JDK1.7比CGLib代理效率低一点,但是到JDK1.8的时候,JDK代理效率高于CGLib代理
Spring AOP通配符配置
Spring AOP 用户可能会经常使用 execution切入点指示符。执行表达式的格式如下:
execution(modifiers-pattern [表示方法的修饰符,可有可无;对应的就是 public]? ret-type-pattern [表示方法的返回值;对应的就是 String] declaring-type-pattern[方法所在类的完全限定名称]? name-pattern(param-pattern)[表示方法的参数;对应的就是 String a, int b]
throws-pattern?)
除了返回类型模式(上面代码片断中的ret-type-pattern),名字模式和参数模式以外, 所有的部分都是可选的。返回类型模式决定了方法的返回类型必须依次匹配一个连接点。 你会使用的 最频繁的返回类型模式是*,它代表了匹配任意的返回类型。 一个全限定的类型名将只会匹配返回给定类型的方法。 名字模式匹配的是方法名。 你可以使用*通配符作为所有或者部分命名模式。 参数模式稍微有点复杂: ()匹配了一个不接受任何参数的方法, 而(..)匹配了一个接受任意数量参数的方法(零或者更多)。 模式(*)匹配了一个接受一个任何类型的参数的方法。 模式(*,String)匹配了一个接受两个参数的方法,第一个可以是任意类型, 第二个则必须是String类型。更多的信息请参阅AspectJ编程指南中 语言语义的部分。
下面给出一些通用切入点表达式的例子。
任意公共方法的执行:
execution(public * *(..))
任何一个名字以“set”开始的方法的执行:
execution(* set*(..))
AccountService接口定义的任意方法的执行:
execution(* com.xyz.service.AccountService.*(..))
在service包中定义的任意方法的执行:
execution(* com.xyz.service.*.*(..))
在service包或其子包中定义的任意方法的执行:
execution(* com.xyz.service..*.*(..))
在service包中的任意连接点(在Spring AOP中只是方法执行):
within(com.xyz.service.*)
在service包或其子包中的任意连接点(在Spring AOP中只是方法执行):
within(com.xyz.service..*)
实现了 AccountService接口的代理对象的任意连接点 (在Spring AOP中只是方法执行):
this(com.xyz.service.AccountService)
'this'在绑定表单中更加常用:- 请参见后面的通知一节中了解如何使得代理对象在通知体内可用。
实现 AccountService接口的目标对象的任意连接点 (在Spring AOP中只是方法执行):
target(com.xyz.service.AccountService)
'target'在绑定表单中更加常用:- 请参见后面的通知一节中了解如何使得目标对象在通知体内可用。
任何一个只接受一个参数,并且运行时所传入的参数是 Serializable 接口的连接点(在Spring AOP中只是方法执行)
args(java.io.Serializable)
'args'在绑定表单中更加常用:- 请参见后面的通知一节中了解如何使得方法参数在通知体内可用。
请注意在例子中给出的切入点不同于 execution(* *(java.io.Serializable)): args版本只有在动态运行时候传入参数是Serializable时才匹配,而execution版本在方法签名中声明只有一个 Serializable类型的参数时候匹配。
目标对象中有一个 @Transactional 注解的任意连接点 (在Spring AOP中只是方法执行)
@target(org.springframework.transaction.annotation.Transactional)
'@target'在绑定表单中更加常用:- 请参见后面的通知一节中了解如何使得注解对象在通知体内可用。
任何一个目标对象声明的类型有一个 @Transactional 注解的连接点 (在Spring AOP中只是方法执行):
@within(org.springframework.transaction.annotation.Transactional)
'@within'在绑定表单中更加常用:- 请参见后面的通知一节中了解如何使得注解对象在通知体内可用。
任何一个执行的方法有一个 @Transactional 注解的连接点 (在Spring AOP中只是方法执行)
@annotation(org.springframework.transaction.annotation.Transactional)
'@annotation'在绑定表单中更加常用:- 请参见后面的通知一节中了解如何使得注解对象在通知体内可用。
任何一个只接受一个参数,并且运行时所传入的参数类型具有 @Classified 注解的连接点(在Spring AOP中只是方法执行)
@args(com.xyz.security.Classified)
'@args'在绑定表单中更加常用:- 请参见后面的通知一节中了解如何使得注解对象在通知体内可用。
任何一个在名为' tradeService'的Spring bean之上的连接点 (在Spring AOP中只是方法执行):
bean(tradeService)
任何一个在名字匹配通配符表达式' *Service'的Spring bean之上的连接点 (在Spring AOP中只是方法执行):
bean(*Service)
execution(modifiers-pattern [表示方法的修饰符,可有可无;对应的就是 public]? ret-type-pattern [表示方法的返回值;对应的就是 String] declaring-type-pattern[方法所在类的完全限定名称]? name-pattern(param-pattern)[表示方法的参数;对应的就是 String a, int b]
throws-pattern?)
除了返回类型模式(上面代码片断中的ret-type-pattern),名字模式和参数模式以外, 所有的部分都是可选的。返回类型模式决定了方法的返回类型必须依次匹配一个连接点。 你会使用的 最频繁的返回类型模式是*,它代表了匹配任意的返回类型。 一个全限定的类型名将只会匹配返回给定类型的方法。 名字模式匹配的是方法名。 你可以使用*通配符作为所有或者部分命名模式。 参数模式稍微有点复杂: ()匹配了一个不接受任何参数的方法, 而(..)匹配了一个接受任意数量参数的方法(零或者更多)。 模式(*)匹配了一个接受一个任何类型的参数的方法。 模式(*,String)匹配了一个接受两个参数的方法,第一个可以是任意类型, 第二个则必须是String类型。更多的信息请参阅AspectJ编程指南中 语言语义的部分。
下面给出一些通用切入点表达式的例子。
任意公共方法的执行:
execution(public * *(..))
任何一个名字以“set”开始的方法的执行:
execution(* set*(..))
AccountService接口定义的任意方法的执行:
execution(* com.xyz.service.AccountService.*(..))
在service包中定义的任意方法的执行:
execution(* com.xyz.service.*.*(..))
在service包或其子包中定义的任意方法的执行:
execution(* com.xyz.service..*.*(..))
在service包中的任意连接点(在Spring AOP中只是方法执行):
within(com.xyz.service.*)
在service包或其子包中的任意连接点(在Spring AOP中只是方法执行):
within(com.xyz.service..*)
实现了 AccountService接口的代理对象的任意连接点 (在Spring AOP中只是方法执行):
this(com.xyz.service.AccountService)
'this'在绑定表单中更加常用:- 请参见后面的通知一节中了解如何使得代理对象在通知体内可用。
实现 AccountService接口的目标对象的任意连接点 (在Spring AOP中只是方法执行):
target(com.xyz.service.AccountService)
'target'在绑定表单中更加常用:- 请参见后面的通知一节中了解如何使得目标对象在通知体内可用。
任何一个只接受一个参数,并且运行时所传入的参数是 Serializable 接口的连接点(在Spring AOP中只是方法执行)
args(java.io.Serializable)
'args'在绑定表单中更加常用:- 请参见后面的通知一节中了解如何使得方法参数在通知体内可用。
请注意在例子中给出的切入点不同于 execution(* *(java.io.Serializable)): args版本只有在动态运行时候传入参数是Serializable时才匹配,而execution版本在方法签名中声明只有一个 Serializable类型的参数时候匹配。
目标对象中有一个 @Transactional 注解的任意连接点 (在Spring AOP中只是方法执行)
@target(org.springframework.transaction.annotation.Transactional)
'@target'在绑定表单中更加常用:- 请参见后面的通知一节中了解如何使得注解对象在通知体内可用。
任何一个目标对象声明的类型有一个 @Transactional 注解的连接点 (在Spring AOP中只是方法执行):
@within(org.springframework.transaction.annotation.Transactional)
'@within'在绑定表单中更加常用:- 请参见后面的通知一节中了解如何使得注解对象在通知体内可用。
任何一个执行的方法有一个 @Transactional 注解的连接点 (在Spring AOP中只是方法执行)
@annotation(org.springframework.transaction.annotation.Transactional)
'@annotation'在绑定表单中更加常用:- 请参见后面的通知一节中了解如何使得注解对象在通知体内可用。
任何一个只接受一个参数,并且运行时所传入的参数类型具有 @Classified 注解的连接点(在Spring AOP中只是方法执行)
@args(com.xyz.security.Classified)
'@args'在绑定表单中更加常用:- 请参见后面的通知一节中了解如何使得注解对象在通知体内可用。
任何一个在名为' tradeService'的Spring bean之上的连接点 (在Spring AOP中只是方法执行):
bean(tradeService)
任何一个在名字匹配通配符表达式' *Service'的Spring bean之上的连接点 (在Spring AOP中只是方法执行):
bean(*Service)
spring AOP应用
事务
类内部方法事务不生效原因解析
JDK动态代理:类内部方法间调用不是通过接口方式调用,不能在方法前后增强
CGLIB动态代理:CGLIB代理重写了父类的非私有方法(原类作为父类,代理类是子类),没有修改父类的字节码,类内调用属于子类调用了父类的方法,父类的方法并没有增强
注解
SpringMVC与Web环境
数据库操作组件的实现
事务处理的实现
Spring远端调用的实现
安全架构ACEGI的设计与实现
SpringDM模块的设计与实现
SpringFlex的设计与实现
0 条评论
下一页