IoC
控制反转(Inversion of Control
)是OOP
中的一种设计原则,也是Spring
框架的核心。通过IoC
则可以减少它们之间的耦合度。有时也叫依赖注入。
在传统的程序设计过程中,通常由调用者来创建被调用者的实例。但在spring
中创建被调用者的工作不再由调用者来完成,因此称为控制反转。
- IoC的主要实现方法是依赖注入DI
依赖注入 : 应用程序被动的接收对象,IoC容器通过类型或名称等信息来判断将不同的对象注入到不同的属性中。
- 依赖注入主要有以下的方式:
1.基于注解 : 通过Java
的注解机制来让IoC
容器注入所依赖类型的对象,例如Spring
框架中的@Autowired
2.基于set
方法 : 实现特定属性的public set()
方法,来让IoC
容器调用注入所依赖类型的对象
3.基于接口 : 实现特定接口以供IoC
容器注入所依赖类型的对象
4.基于构造函数 : 实现特定参数的构造函数,在创建对象时来让IoC
容器注入所依赖类型的对象
@Autowired
注释,它可以对类成员变量、方法及构造函数进行标注,完成自动装配的工作。 通过 @Autowired
的使用来消除 set ,get
方法。
在使用@Autowired
之前,我们对一个bean
配置起属性时,是这样用的:
<bean id="" class="" atuowire="byName">
<property name="属性名" value=" 属性值"/>
</bean>
- byName
会自动在容器上下文中,查找和自己对象set方法后面的值对应的bean id,需要保证bean id唯一 - byType
会自动在容器上下文中,查找和自己对象属性类型相同的bean(根据bean中class=""),需要保证bean class唯一
通过这种方式来,配置比较繁琐,而且代码比较多。在Spring 2.5
引入了@Autowired
注释。
@Autowired
注解是按照类型(byType
)装配依赖对象,默认情况下它要求依赖对象必须存在,如果允许null
值,可以设置它的required
属性为false
。如果我们想使用按照名称(byName
)来装配,可以结合@Qualifier
注解一起使用。如下:
public class TestServiceImpl {
@Autowired
@Qualifier("userDao")
private UserDao userDao;
}
- 使用@Autowired的原理是什么
当 Spring
容器启动时,AutowiredAnnotationBeanPostProcessor
将扫描 Spring
容器中所有 Bean
,当发现 Bean
中拥有 @Autowired
注释时就找到和其匹配(默认按类型匹配)的 Bean
,并注入到对应的地方中去。 即会在IoC
容器自动查找需要的bean
,并装配给该对象的属性。
AOP(Aspect-Oriented Programming)
即面向切面编程。
AOP
解决了代码的重复并将这些外围业务代码抽离到一个切面中,我们可以动态地将切面切入到切入点。
spring相关—AOP编程—切入点、连接点
- target目标类:需要被代理的类,例如UserService
- joinpoint连接点:那些可能被拦截的方法,列如所有方法
- pointcut切入点:已经被通知的连接点。例如addUser()
- advice通知代码:例如after,before
- proxy:代理类
- weaving织入:把增强advice应用到target来创建proxy的过程-
-
aspect切面:pointcut和advice的结合
aop术语3.PNG
AspectJ
AspectJ是基于java的aop框架
AspectJ的通知类型
- before:前置通知(应用:各种校验)
在方法执行前执行,如果通知抛出异常,阻止方法运行 - afterReturning:后置通知(应用:常规数据处理)
方法正常返回后执行,如果方法中抛出异常,通知无法执行。必须在方法执行后才执行,所以可以获得方法的返回值。 - around(before+afterReturning):环绕通知(应用:十分强大,可以做任何事情)
切入的方法执行前后(对应通知的joinPoint.proceed前后)分别执行,如下。
System.out.println("EXECUTION 首个参数:" + point.getArgs()[0]);
point.proceed();
System.out.println("EXECUTION success");
我们必须要执行目标方法joinPoint.proceed。
around做接口校验,如果直接return point.proceed(),那么aop会拦截,不继续往下走。
如果切入的方法不确定有没有返回值,环绕方法要返回Object。
- afterThrowing:抛出异常通知(应用:包装异常信息)
方法抛出异常后执行,如果方法没有抛出异常,无法执行通知 - after:最终通知(应用:清理现场)
方法执行完毕后执行,无论方法中是否出现异常,通知都会执行
AspectJ基于注解
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
// 切面(切入点和通知代码的结合)
@Aspect
public class test {
// 切入点(有execution、within、this、target、args等Pointcut表示式)
@Pointcut("@within(RestController)")
public void addPointcut() {
}
// 前置通知(在RestController里面的方法运行前执行此addAdvice方法)
// 如果addAdvice方法抛出异常,阻止RestController中方法的运行
@Before("addPointcut()")
public void addAdvice(JoinPoint joinPoint) {
}
}
网友评论