文章目录
Spring AOP
一、AOP概念
1.为什么要有AOP思想?
1.在java面向对象阶段:类中代码复用可以用继承解决。
B extends A
2.新问题:当方法中出现重复的代码,如何复用?在不修改原方法的情况下,如何做业务修改?
独立出重复的方法:before() after()。但在单个方法中仍需重复。
//独立出重复的方法:before() after()。但在方法中仍需重复。
class A{
public void a(){
before();
语句1
after();
}
public void b(){
before();
语句2
after();
}
private void before(){//重复方法
{
//代码块1
}
}
private void after(){//重复方法
{
// 代码块2
}
}
}
解决方法: 面向切面(多个方法方法)的开发
创建一个aop切a和b方法,自动在方法的语句前在before方法,语句后加after方法。
这就是面向切面的思想
class A{
public void a(){
语句1
}
public void b(){
语句2
}
}
class Aop{
public void before(){
{
//代码块1
}
}
public void after(){
{
// 代码块2
}
}
}
2.AOP的是什么
关键词: 面向切面编程 对业务隔离 降低耦合度(解耦)
实现原理: 代理模式
AOP(Aspect Oriented Programming)意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。
AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
流程
- 横切关注点:跨越应用程序多个模块的方法或功能。即是,与我们业务逻辑无关的,但是我们需要关注的部分,就是横切关注点。如日志,安全,缓存,事务等等…
- 切面(ASPECT) :横切关注点被模块化的特殊对象。即,它是一个类。比如日志类
- 通知(Advice) :切面必须要完成的工作。即,它是类中的一个方法。
- 目标(Target) :被通知对象,就是要实现关注点的接口
- 代理(Proxy) :向目标对象应用通知之后创建的对象。就是代理类
- 切入点(PointCut):切面通知执行的“地点”的定义。
- 连接点(JointPoint) :与切入点匹配的执行点。
二、AOP的实现原理——代理模式
代理模式就是隐藏真实对象,使用代理对象去操作真实对象。这样保护真实对象,也方便后期在不修改真实对象代码的情况下修改业务。
Demo:假设小明准备租三室一厅的房子,找访问中介租房,中介将房东的房子租给小明。
房东:真实对象(real)
中介:代理对象
通过代理对象取操作真实对象
1.静态代理
public interface IRent { //租房接口
void rent();
}
//房东
public class HouseKeeper implements IRent {
@Override
public void rent() {
System.out.println("出租豪华三室一厅");
}
}
//中介
public class HouseAgent implements IRent {
private IRent real;
public HouseAgent(IRent real) {
this.real = real; //指向irent对象
}
@Override
public void rent() {
this.real.rent();
}
}
@Test
public void test() {
IRent real = new HouseKeeper();
IRent agent = new HouseAgent(real);
agent.rent();
}
--------------------
出租豪华三室一厅
静态代理的优点:
1.隐藏真实对象(Real)
2.代理对象的方法进行功能添加修改。可以增删方法
静态代理的缺点: 接口不可变的
2.动态代理(JDK实现,InvocationHandler)
JDK已经实现了动态代理,接口变更之后,切入的接口方法可以变更。
动态代理的接口:InvocationHandler
public interface IRent {
void rent();//租房
void job(); //找工作
void c(); //其它方法......
}
public class HouseKeeper implements IRent {
@Override
public void rent() {
System.out.println("出租豪华三室一厅");
}
@Override
public void job() {
System.out.println("找工作");
}
@Override
public void c() {
System.out.println("C");
}
}
//实现InvocationHandler接口
public class AgentMaker implements InvocationHandler {
private Object real; //传入的真实对象
public AgentMaker(IRent real) {
this.real = real;
}
/**
* 产生代理对象
* @return
*/
public IRent createAgent() {
return (IRent) Proxy.newProxyInstance(real.getClass().getClassLoader(),
real.getClass().getInterfaces(), this); //(获取类加载器,获取接口对象,当前对象的引用 irent类) 反射技术
}
/**
* 调用真实对象的方法
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
before();
Object retVal = method.invoke(this.real, args);
after();
return retVal;
}
private void before() {
System.out.println("收取2500押金");
}
private void after() {
System.out.println("每月检查卫生一次,不合格罚款100元");
}
}
@Test
public void test() {
HouseKeeper real = new HouseKeeper();
IRent r = new AgentMaker(real).createAgent();
r.rent();
r.job();
}
----------------------------
收取2500押金
出租豪华三室一厅
每月检查卫生一次,不合格罚款100元
收取2500押金
找工作
每月检查卫生一次,不合格罚款100元
3.cglib代理(通过字节码实现)
动态代理问题:如果真实对象没有实现任何接口,使用cglib代理
继承机制:子类继承父类的方法:覆盖
package com.dyit.service.impl;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class AgentMaker implements MethodInterceptor {
private Object real;
public AgentMaker(Object real) {
this.real = real;
}
public Object createProxy() {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(real.getClass());
enhancer.setCallback(this);
return enhancer.create();
}
private void before() {
System.out.println("收取2500押金");
}
private void after() {
System.out.println("每月检查卫生一次,不合格罚款100元");
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
before();
Object retVal =proxy.invokeSuper(obj, args);
after();
return retVal;
}
}
三、aop的相关概念
- 目标对象(target): 要进行操作的对象
- 切面(Aspect): 要插入(切入、注入)的代码的业务逻辑
- 连接点(JoinPoint):连接的方法(其中的一个方法)
- 切点:多个方法(定义规则)
advise(增强)切的方式
- Before
- After
- Around
- AfterReturning
- Excetpion
aop实例
1. 建立切面
@Aspect
@Service
public class BookServiceAop {
@Around("execution(* com.dyit.ssm.service.impl.*.*(..))")
public Object testAround(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("准备切方法:" + pjp.getSignature());
Object retVal = pjp.proceed();// 目标对象执行的方法
System.out.println("切入完成:,准备离开......");
return null;
}
}
2.确定增强方式(advise)
@Around:环绕切
3.定义切点
规则 execution(* 包 . * . *books(String))
//*books(…) 切以books类结尾的任意方法
4.实现代码
5.配置
在 xml文件里面加上
<aop:aspectj-autoproxy/> //自动配置 默认使用动态代理