IOC和AOP的理解以及动态代理

IOC(Inversion of Control,控制反转):

IOC容器是Spring框架中的核心。在Spring框架中,所有的类都将在Spring容器中登记,告诉Spring这个类是什么,需要什么,然后Spring会在系统运行到适当的时候把需要到的类主动提交,同时也会把这个类提交给其他需要到的类中。所有的类的创建和销毁都是由Spring来控制,也就是说控制对象生存周期的不再是引用它的对象,而是Spring。对于某个具体的对象而言,以前是它控制其他对象,现在是所有的对象都由Spring来控制,所以这就叫控制反转。

DI(Dependency Injection,依赖注入):

IOC的一个重点是在系统运行中,动态的向某个对象提供它所需要的其他对象。这一点是通过DI来实现的。比如说当对象A需要操作数据库,以前我们总是要在A中自己编写代码来获得一个Connection对象,而在Spring中只需要告诉Spring,A中需要一个Connection,至于这个Connection怎么构造,何时构造,A不需要知道。在系统运行的时候,Spring会在适当的时候制造一个Connection,然后像打针一样注入到A中,这样就完成了对各个对象之间关系的控制。A需要依赖Connection才能正常运行,而这个Connection是由Spring注入到A中的,依赖注入的名字就是这么来的。那么DI是怎么实现的呢?在Java1.3之后一个重要的特征就是反射(reflection),它允许程序在运行的时候动态生成对象、执行对象的方法、改变对象的属性,Spring就是通过反射来实现依赖注入的。


AOP(Aspect Oriented Programming,面向切面编程):

AOP是对OOP的完善和增强。在OOP思想中,我们会把人的身高、体重、年龄等属性和跑步、吃饭、睡觉等行为封装在一个people类中,然后以统一调用的方式(创建一个people类的实例对象,通过这个对象实例来调用这些属性和行为)。OOP给我们的感觉就是结构清晰,高内聚,易维护等。这些属于一种从上到下的关系(即这个类封装的所有属性和方法都是属于people的),而AOP思想就是一种从左到右的关系,以切入的方式将业务逻辑功能应用到每一层结构中(可以理解为类方法,类方法也是一种对象的行为实现)。举个例子,人如果生病了就需要去医院看病,但是去医院看病这一个业务逻辑功能并不是属于哪一个类,而是谁生病了,谁就需要去医院看病,而基于OOP思想,我们是不可能把这一个业务逻辑添加到每一个类中的,这不符合OOP思想,而这个,就是AOP所做的事情了。AOP就是把医院看病这一个业务逻辑功能抽取出来,然后动态的把这个功能注入到需要的方法(或行为)中,以后,不管是谁需要看病,就到医院这个第三方机构看病(AOP就相当于把这个第三方机构给独立出来)。这样从业务逻辑角度上,AOP达到了更进一步的解耦,所以我们称AOP是对OOP的完善和增强。

而在我们的编程中,常用到AOP的就是安全校验、日志操作、事务操作等。AOP把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是:他们经常发生在核心关注点的多出,而各处都基本相似。比如权限认证、日志、事务处理。AOP的作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来。

AOP的相关术语:

1.Advice(通知):

就是你想要的功能,也就是上面说的安全、日志、事务等。你先定义好,然后在想用的地方用一下。

2.JoinPoint(连接点):

就是Spring允许你使用通知的地方,基本上是每个方法的前,后或抛出异常时都可以时连接点。

3.PointCut(切入点):

在连接点的基础上定义切入点。在一个类中,可能有多个方法,但是如果只想在调用其中几个方法之前(之后或抛出异常时干点什么),那么就可以使用切点来定义这几个方法,让切点来筛选连接点,选中你想要的那几个方法。

4.Aspect(切面):

切面就是通知和切入点的结合。在实际中,没有连接点的事,连接点只是让人更好的理解切入点而产生的。通知说明了干什么和什么时候干(什么时候干是通过方法名中的before、after、around等就能知道),而切入点说明了在哪里干(指定到底是哪个方法),这就是一个完整的切面定义。

5.Introduction(引入):

允许我们向现有的类添加新的方法属性。这就是把切面(也就是新方法属性,通知定义的)用到目标类中。

6.Target(目标):

一如中所提到的目标类,也就是要被通知的对象,也就是真正的业务逻辑,它会在毫不知情的情况下被织入切面,而他自己本身只专注于自身的业务逻辑。

7.proxy(代理):

整套AOP机制都是通过代理来实现的,也就是说,AOP的实现原理是基于动态代理实现的。

8.weaving(织入):

把切面应用到目标对象来创建新的代理对象的过程。


动态代理的方式:

代理方式分为静态代理和动态代理两种。

静态代理:

静态代理就是自己手写代理类,有两种思路:一是通过继承被代理类的方式实现其子类,重写父类方法;二是与被代理类实现共同的一个接口(需要代理类实现了接口)。

动态代理:

动态代理,简单的来说就是交给程序去自动生成代理类(在程序运行期间由JVM根据反射等动态生成源码)。动态代理的实现也有两种:一是基于接口的JDK动态代理;二是基于继承的cglib动态代理。

JDK的动态代理:

使用JDK的动态代理只需要一行代码。

Moveable move = (Moveable) Proxy.newProxyInstance(Car.class.getClassLoader(), Car.class.getInterfaces(), new LogHandler(new Car()));

传入的参数中其实就两个,一是被代理类的对象,二是自定义的增强处理代码。

JDK的动态代理只能代理实现了接口的类, 没有实现接口的类不能实现动态代理。

cglib的动态代理:

cglib使用动态代理的流程:

public static void main(String[] args){
  Enhancer enhancer = new Enhancer();
  // 设置被代理类
  enhancer.setSuperclass(Car.class);
  // 设置回调函数
  enhancer.setCallback(new MethodInterceptor(){
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MehodProxy proxy) throws Throwable{
      Object o = proxy.invokeSuper(obj, args);// 代理类调用父类的方法
      return o;
    }
  });
  // 创建代理类并使用回调
  Car car = (Car)enhancer.create();
  // 执行目标方法
  System.out.println(car.move());
}

从上面的代码看到,cglib的使用流程还是很清晰明了,各种参数顾名思义,和jdk的区别不大。生成的代理对象直接被该类引用,与我们认知的基于继承的动态代理没冲突。不过这种基于继承的方式就没有什么缺点吗?最明显的一点就是final修饰的类无法使用。


Spring用的什么代理方式?

Spring会根据具体的Bean是否具有接口去选择动态代理方式,如果有接口,使用的是Jdk的动态代理方式,如果没有接口,使用的是cglib的动态代理方式。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值