Hello,今天给各位童鞋们分享Spring IOC,赶紧拿出小本子记下来吧!
1. 初识AOP
1.1 什么是AOP
AOP 为 Aspect Oriented Programming 的缩写,意思为面向切面编程。
AOP 是 OOP(面向对象编程) 的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
优点
在程序运行期间,在不修改源码的情况下对方法进行功能增强
逻辑清晰,开发核心业务的时候,不必关注增强业务的代码
减少重复代码,提高开发效率,便于后期维护
1.2 AOP底层实现
实际上,AOP 的底层是通过 Spring 提供的动态代理技术实现的。在运行期间,Spring通过动态代理技术动态的生成代理对象,代理对象方法执行时进行增强功能的介入,再去调用目标对象的方法,从而完成功能的增强。
常用的动态代理技术
我们可以将业务代码和事务代码进行拆分,通过动态代理的方式,对业务方法进行事务的增强。这样就不会对业务层产生影响,解决了耦合性的问题。
JDK动态代理方式
基于接口的动态代理技术·:利用拦截器(必须实现invocationHandler)加上反射机制生成一个代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理,从而实现方法增强。
CGLIB动态代理方式
基于父类的动态代理技术:动态生成一个要代理的子类,子类重写要代理的类的所有不是final的方法。在子类中采用方法拦截技术拦截所有的父类方法的调用,顺势织入横切逻辑,对方法进行增强。
在 Spring 中,框架会根据目标类是否实现了接口来决定采用哪种动态代理的方式。
当bean实现接口时,会用JDK代理模式
当bean没有实现接口,用cglib实现( 可以强制使用cglib:在spring配置中加入<aop:aspectj-autoproxy proxyt-target-class=”true”/>)
1.3 AOP开发明确事项
1.3.1 开发阶段(我们做的)
编写核心业务代码(目标类的目标方法) 切入点
把公用代码抽取出来,制作成通知(增强功能方法) 通知
在配置文件中,声明切入点与通知间的关系 切面
1.3.2 运行阶段(Spring框架完成的)
Spring 框架监控切入点方法的执行。一旦监控到切入点方法被运行,使用代理机制,动态创建目标对象的代理对象,根据通知类别,在代理对象的对应位置,将通知对应的功能织入,完成完整的代码逻辑运行。
2. 基于注解的AOP开发
步骤分析
- 创建java项目,导入AOP相关坐标
- 创建目标接口和目标实现类(定义切入点)
- 创建通知类(定义通知)
- 将目标类和通知类对象创建权交给spring
- 在通知类中使用注解配置织入关系,升级为切面类
- 在配置文件中开启组件扫描和 AOP 的自动代理
- 编写测试代码
1)创建java项目,导入AOP相关坐标
2)创建目标接口和目标实现类
public interface AccountService {
public void transfer();
}
3)创建通知类
public class MyAdvice {
public void before() {
System.out.println("前置通知...");
}
}
4)将目标类和通知类对象创建权交给spring
@Service
public class AccountServiceImpl implements AccountService {}
@Component
public class MyAdvice {}
5)在通知类中使用注解配置织入关系,升级为切面类
@Component
@Aspect //升级为切面类:配置切入点和通知的关系
public class MyAdvice {
@Before("execution(* com.lagou...(..))")
public void before() {
System.out.println("前置通知...");
}
}
6)在配置文件中开启组件扫描和 AOP 的自动代理
<context:component-scan base-package="com.lagou"/>
aop:aspectj-autoproxy</aop:aspectj-autoproxy>
7)编写测试代码
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
class AccountServiceTest {
@Autowired
private AccountService accountService;
@Test
public void testTransfer() throws Exception {
accountService.transfer();
}
}
切点表达式
表达式语法:
execution([修饰符] 返回值类型 包名.类名.方法名(参数))
- 访问修饰符可以省略
- 返回值类型、包名、类名、方法名可以使用星号 * 代替,代表任意
- 包名与类名之间一个点 . 代表当前包下的类,两个点 … 表示当前包及其子包下的类
- 参数列表可以使用两个点 … 表示任意个数,任意类型的参数列表
切点表达式抽取
当多个增强的切点表达式相同时,可以将切点表达式进行抽取,在增强中使用 pointcut-ref 属性代替 pointcut 属性来引用抽取后的切点表达式。
通知类型
通知的配置语法:@通知注解(“切点表达式")
知识小结
-
使用@Aspect注解,标注切面类
-
使用@Before等注解,标注通知方法
-
使用@Pointcut注解,抽取切点表达式
-
配置aop自动代理 aop:aspectj-autoproxy/ 或 @EnableAspectJAutoProxy(纯注解,编写SpringConfig类)
好啦,今天的文章就到这里,希望能帮助到屏幕前迷茫的你们