依赖注入(Dependecy Injection)和控制反转(Inversion of Control)是同一个概念,具体的讲:当某个角色
需要另外一个角色协助的时候,在传统的程序设计过程中,通常由调用者来创建被调用者的实例。但在spring中
创建被调用者的工作不再由调用者来完成,因此称为控制反转。创建被调用者的工作由spring来完成,然后注入调用者
因此也称为依赖注入。
spring以动态灵活的方式来管理对象 , 注入的两种方式,设置注入和构造注入。
设置注入的优点:直观,自然
构造注入的优点:可以在构造器中决定依赖关系的顺序。
原理区别:
java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。而cglib动态代理是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。
1、如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP
2、如果目标对象实现了接口,可以强制使用CGLIB实现AOP
3、如果目标对象没有实现了接口,必须采用CGLIB库,spring会自动在JDK动态代理和CGLIB之间转换
如何强制使用CGLIB实现AOP?
* 添加CGLIB库,SPRING_HOME/cglib/*.jar
* 在spring配置文件中加入<aop:aspectj-autoproxy proxy-target-class="true"/>
JDK动态代理和CGLIB字节码生成的区别?
* JDK动态代理只能对实现了接口的类生成代理,而不能针对类
* CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法
因为是继承,所以该类或方法最好不要声明成final
Spring Aop 要拦截某些类的话,那会判断这个类是否实现了接口,如果实现了接口就会用jdk 动态代理来创建代理对象;如果没有这个类没有实现接口情况下,则用CGLIB来创建代理对象;
JDK动态代理
- public class JDKProxy implements InvocationHandler {
- private Object targetObject;//代理的目标对象
- public Object createProxyInstance(Object targetObject){
- this.targetObject = targetObject;
- /*
- * 第一个参数设置代码使用的类装载器,一般采用跟目标类相同的类装载器
- * 第二个参数设置代理类实现的接口
- * 第三个参数设置回调对象,当代理对象的方法被调用时,会委派给该参数指定对象的invoke方法
- */
- return Proxy.newProxyInstance(this.targetObject.getClass().getClassLoader(),
- this.targetObject.getClass().getInterfaces(), this);
- }
- public Object invoke(Object proxy, Method method, Object[] args)
- throws Throwable {
- return method.invoke(this.targetObject, args);//把方法调用委派给目标对象
- }
- }
当目标类实现了接口,我们可以使用jdk的Proxy来生成代理对象。
- public class CGLIBProxy implements MethodInterceptor {
- private Object targetObject;//代理的目标对象
- public Object createProxyInstance(Object targetObject){
- this.targetObject = targetObject;
- Enhancer enhancer = new Enhancer();//该类用于生成代理对象
- enhancer.setSuperclass(this.targetObject.getClass());//设置父类
- enhancer.setCallback(this);//设置回调用对象为本身
- return enhancer.create();
- }
- public Object intercept(Object proxy, Method method, Object[] args,
- MethodProxy methodProxy) throws Throwable {
- return methodProxy.invoke(this.targetObject, args);
- }
- }
- CGLIB可以生成目标类的子类,并重写父类非final修饰符的方法。