一.spring容器有两大核心功能IOC(控制反转)和AOP(面向切面编程).
IOC:为我们创建和管理对象,还可以维护对象之间的关系,不仅使代码简洁易懂,而且耦合度大大降低.
AOP:使核心业务和其他业务分离,不仅减少了代码量,而且有利于协作开发
二.SpringAOP功能是如何实现的?
是基于动态代理实现的.
三.什么是动态代理,什么是静态代理?
1.代理的基本构成:
抽象角色:声明真实对象和代理对象的共同接口(interface).
代理角色:代理对象内部含有真实对象的引用,从而在任何时候都可以操作真实对象.(其他业务问题+核心问题)
真实角色:是我们最终要引用的对象(解决核心问题)
2.静态代理
2.1创建抽象角色
public interface Subject {//抽象角色
public void doSomething();
}
2.2创建真实角色
public class RealSubject implements Subject {//真实角色
@Override
public void doSomething() {
System.out.println("doSomething()");
}
}
2.3创建代理角色
public class SubjectProxy implements Subject {//代理角色
//包含真实对象的引用,能够操作真实对象
Subject subImpl = new RealSubject();
@Override
public void doSomething() {
System.out.println("before");//调用目标对象之前可以执行操作
subImpl.doSomething();
System.out.println("after");//调用目标对象之后可以执行操作
}
}
2.4创建测试类测试
public class Test {
public static void main(String[] args) {
Subject subject = new SubjectProxy();
subject.doSomething();
}
}
结果为:
3.静态代理的缺点
3.1.当真实角色实现了新的接口后,代理类需要和真实角色一样实现此接口,也需要添加此接口的引用,代理类会变得 臃肿
3.2.当真实角色改变接口时,代理类需要改变接口引用
总之:静态代理中真实角色和代理角色有强耦合关系,不利于代码的拓展和维护
4.JDK动态代理
基于java反射机制解决静态代理的缺点
4.1创建抽象角色(同静态代理)
4.2创建真实角色(同静态代理)
4.3创建代理角色
package proxyHandlerTest01;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyHandler implements InvocationHandler {
private Object tar;
/**
* 绑定委托对象,获取代理类
* @param tar 目标对象
* @return 代理类
*/
public Object bind(Object tar){
this.tar = tar;
//绑定该类实现的所有接口,取得代理类
return Proxy.newProxyInstance(tar.getClass().getClassLoader(),
tar.getClass().getInterfaces(), this);
}
/**
* 此方法不会显式地调用
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = null;
System.out.println("before");
result = method.invoke(tar, args);
System.out.println("after");
return result;
}
}
4.4测试代理类
package proxyHandlerTest01;
import java.lang.reflect.Proxy;
public class Test {
public static void main(String[] args) throws NoSuchMethodException, SecurityException, Throwable {
ProxyHandler proxy = new ProxyHandler();
Subject subject = (Subject)proxy.bind(new RealSubject());
subject.doSomething();
System.out.println("\n代理类是否继承Proxy类:"+(subject instanceof Proxy));
System.out.print("代理类实现的接口为:");
Class<?>[] cls = subject.getClass().getInterfaces();
for(Class<?> c:cls){
System.out.println(c);
}
System.out.println("代理类名称为:"+subject.getClass().toString());
}
}
测试结果为:
总结: 1.JDK动态代理利用java反射机制简单粗暴的为目标对象创建代理对象
2.JDK动态代理解决了静态代理的缺点,不论目标类怎么变化,代理类不需要改变!
3.该对象继承Proxy类,实现目标对象的所有接口
4.JDK动态代理核心为:Proxy类和invocationHandler回调接口(面试常问)
注意:JDK动态代理只适用于目标类实现了接口!!
四.除了JDK动态代理,SpringAOP还有cglib动态代理
cglib动态代理解决了JDK动态代理的缺点,它可以为不实现接口的目标对象动态创建代理类
区别于JDK动态代理底层原理基于java反射,cglib动态代理的底层是通过一个字节码处理框架asm,来转换字节码并生成新的类.
cglib核心:
MethodInterceptor:实现此接口可以定义方法的拦截器,即定义拓展功能
Enhancer:生成代理类的字节码
注意: 1.生成的代理类继承了目标类,所以调用目标类的方法时,会执行代理类的方法
2.由于目标类需要被代理类继承,所以目标类如果带有final修饰词,则无法使用cglib生成代理类!