IoC(Inversion of Control):
在传统的java程序编写中如果调用方法或类者,必须要对被调用者进行实例化,即必须要通过new 被调用者类
,才能对被调用者类中的方法、成员进行操作。在开发某一个项目时必然会出现很多类来完善项目的需求,并且类与类之间有很多的交互和依赖,代码将会很变得很难高度耦合和有效的维护。spring中的IoC便解决了这一问题。IoC即控制反转,它主要是将控制权原本由被调用者转换成spring的容器。也就是说由spring生成(实例化)这些对象,并控制这些类的调用。IoC还有一种叫法是DI(Dependency Injection),即依赖注入。在spring容器启动的时候就会自动的将一些类、方法、成员装入一个bean容器中,在之后调用者调用这些类、方法、成员时就不需要再次实例化。这样可以避免多次对被调用者进行实例化,调用者不需要再像之前有那么多重复的操作。
简单来说,spring的IoC就好比是一个餐厅,在餐厅开饭之前厨师已经通过之前的很多步骤做好了很多菜。等到开饭后,很多买饭者可以任意挑选自己喜欢吃的菜,但是不需要关心这些菜的做法及过程,只管尽情的享用即可。
AOP(Aspect Oriented Programming):
AOP即面向切面编程。个人理解是将一个本身完整的东西,但是因为需要对操作者增加一些权限,必须将这个东西切开,然后给里面加一些想要的拦截。比如说一个酒店服务员你可以给顾客端茶递水,但是一个酒店打扫卫生的员工就不允许给顾客端茶递水。所以就需要酒店经理提前给这些员工分配自己的工作范围。
spring实现AOP需要引入java中的代理,其主要目的是为了增加拦截器。在java中有两种代理方式,JDK代理和CGLIB代理。前者代理需要本实现一个接口,在代理这个类时只能代理接口中的类。后者代理不需要实现接口,但是对于本类中的final方法不能进行代理。具体代理方式自行查看。
先看看我实现IOC和AOP的总体思路框图
接下来看看代码的简单实现
首先是一个SatProxy类,其中共有三个成员,成员的get()和set()方法就不写了
private Object proxy; //代理对象//代理类的本对象
private Object object; //代理类的本对象
private boolean isInjection; //判断成员是否注入
在这个类中还有三个拦截器方法。分别为doBefore()、doAfter()、dealException()。其主要是为了对一些需要拦截的方法进行置前、置后、异常拦截(为了简单只写了这三个拦截方法,spring中还有其他拦截方法)
protected boolean doBefore(Object[] args, Class<?> klass, Method method) {
IntercepterFactory intercepterFactory = new IntercepterFactory(); //拦截器工厂
IntercepterTargetDefination itd = new IntercepterTargetDefination
(klass, method); //通过从ProxyFactory中传过来的method,klass确定目标拦截方法
List<IntercepterMethodDefination> intercepterMethodList =
intercepterFactory.getBeforeMethodList(itd); //通过目标拦截方法找到拦截方法List
if (intercepterMethodList == null) { //如果没有找到相关的拦截器
return true;
}
for (IntercepterMethodDefination imd : intercepterMethodList) {
Method intercepterMethod = imd.getMethod();
Object object = imd.getObject();
boolean result = false;
try {
result = (boolean)intercepterMethod.invoke(object, args); //反射拦截方法
return result;
} catch (Exception e) {
e.printStackTrace();
}
}
return true;
}
上面代码中提到了IntercepterFactory类,那我们先来看看这个类
在上面的框图中所提到的InteecepterMethodDefination类中有成员的get()和set()方法、IntercepterTargetDefination类有equas()方法
在下面的代码中只写出了addBeforeMap()、getbeforeMethodList()方法,其他的addAfterMap()、addExceptionMap()、getbeforeMethodList()、getbeforeMethodList()与它们相似,这里就不再写出来
public class IntercepterFactory {
private static final Map<IntercepterTargetDefination, List<IntercepterMethodDefination>> beforeMap;
private static final Map<IntercepterTargetDefination, List<IntercepterMethodDefination>> afterMap;
private static final Map<IntercepterTargetDefination, List<IntercepterMethodDefination>> exceptionMap;
static {
beforeMap = new HashMap<>();
afterMap = new HashMap<>();
exceptionMap = new HashMap<>();
}
private void addIntercepterMap(
Map<IntercepterTargetDefination, List<IntercepterMethodDefination>> map,
IntercepterTargetDefination intercepterTarget,
IntercepterMethodDefination intercepterMethod) {
List<IntercepterMethodDefination> methodList = map.get(intercepterTarget);
if (methodList == null) { //若methodLIst没有产生则执行以下代码,否则直接将拦截器加入List
synchronized (IntercepterFactory.class) { //锁住该类
if (methodList == null) {
methodList = new ArrayList<>();
map.put(intercepterTarget, methodList);
}
}
}
methodList.add(intercepterMethod);
}
// 往Map中添加成员
protected void addBeforeMap(IntercepterTargetDefination intercepterTarget,
IntercepterMethodDefination intercepterMethod) {
addIntercepterMap(beforeMap, intercepterTarget, intercepterMethod);
}
// 通过目标拦截方法获取拦截方法
protected List<IntercepterMethodDefination> getBeforeMethodList(
IntercepterTargetDefination intercepterTarget) {
return beforeMap.get(intercepterTarget);
}
}
在上述类中使用synchronized,是为了保证三个List都是单例的。也就是执行一次所有的方法只能各有一个这样的List,也就是说将所有的before拦截、after拦截、exception拦截都各自保存在一个List中。其中三个Map也都应该是单例的
在ProxyFactory类中产生CGLIB/JDK代理,其中有SatProxy类的成员,并有其set()、get()方法。
public class ProxyFactory {
private SatProxy satProxy;
protected <T> T getCGLProxy(Object object, Class<?> klass) {
T proxy = CGLProxy(object, klass);
satProxy = new SatProxy();
satProxy.setProxy(proxy); //将代理加入SatProxy类中
satProxy.setObject(object); //将原对象加入SatProxy类中
return proxy;
}
@SuppressWarnings("unchecked")
private <T> T CGLProxy(Object object, Class<?> klass) { //产生CGLIB代理
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(klass);
MethodInterceptor methodInterceptor = new MethodInterceptor() {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
Object result = invokeMethod(klass, object, method, args); //调用本类下的反射方法
return result;
}
};
enhancer.setCallback(methodInterceptor);
return (T) enhancer.create();
}
// 反射方法
private Object invokeMethod(Class<?> klass, Object object, Method method, Object[] args) throws Throwable {
Object result = null;
// 置前拦截
if (satProxy.doBefore(args, klass, method) == false) {
return null;
}
try {
result = method.invoke(object, args);
// 置后拦截
result = satProxy.doAfter(result, klass, method);
} catch (Throwable e) {
// 异常拦截
satProxy.doDealException(klass, e, method);
throw e;
}
return result;
}
}
产生JDK的代理的方法与产生CGLIB代理的方法相似
在ProxyBeanFactory类中的方法调用ProxyFactory类中的方法。在下面的代码中只有产生CGLIB代理的方法
public class ProxyBeanFactory {
private static final Map<String, SatProxy> beanMap; //将扫描到的类或方法产生的代理和类名称保存
private static final Map<String, String> beanNameMap; //将扫描到的类或方法注解中带有的name和类名字保存
static {
beanMap = new HashMap<>();
beanNameMap = new HashMap<>();
}
protected void addBeanNameMap(String beanName, String klassName) throws Exception {
String orgClassName = beanNameMap.get(beanName);
if(orgClassName != null) { //如果已经加入Map就抛出异常
throw new ClassNameAlreadyExistException("bean(" + beanName + ")重复");
}
beanNameMap.put(beanName, klassName);
}
protected SatProxy getSatProxy(String klassName) {
return beanMap.get(klassName);
}
protected <T> T getProxy(Class<?> klass) {
SatProxy satProxy = beanMap.get(klass.getName());
return satProxy.getProxy(); //返回一个代理,注意:不是satProxy
}
protected void creatCGLProxy(Class<?> klass) throws Exception { //产生一个代理
cglProxy(klass.newInstance(), klass);
}
private void cglProxy(Object object, Class<?> klass) {
String klassName = klass.getName();
SatProxy satProxy = beanMap.get(klassName);
if(satProxy != null) { //如果已经存在,直接return
return;
}
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.getCGLProxy(object, klass); //真正的产生一个代理
beanMap.put(klassName, proxyFactory.getSatProxy()); //将产生的代理和类名称加入Map
}
}
在上述类中之所以将Map写为static final的是为了保证每次产生的Map都是单例的,换句话说是为了将扫描到的类或方法都存到同一个Map中
我们把上述这些基本的类准备好之后就可以开始使用BeanFactory类扫描包(可能会觉得代码有点长,但是每一步都不可少)
public class BeanFactory {
public BeanFactory() {
}
public static void scanPackage(String packageName) {
ProxyBeanFactory proxyBeanFactory = new ProxyBeanFactory(); //产生一个对象
List<BeanMethodDefination> beanMethodList = new ArrayList<>(); //保存有参数的方法(后面会讲BeanMethoddefination类)
new PackageScanner() { //扫描包(自己的工具)
@Override
public void dealClass(Class<?> klass) { //扫描包中类
if (!klass.isAnnotationPresent(Component.class)) { //如果没有@Component注解,直接return
return;
}
Component component = klass.getAnnotation(Component.class);
String name = component.name(); //得到注解中的name
try {
String klassName = klass.getName();
createBean(proxyBeanFactory, klass, null, name); //创建一个该类的代理(加入beanMap)
SatProxy satProxy = proxyBeanFactory.getSatProxy(klassName);
Object object = satProxy.getObject(); //得到Klass类的原对象
Method[] methods = klass.getDeclaredMethods(); //得到该类的所有方法
for (Method method : methods) {
if (!method.isAnnotationPresent(Bean.class)) { //若该方法中没有@Bean注解,则继续扫描下一个方法
continue;
}
invokeBeanMethod(proxyBeanFactory, object, method, beanMethodList); //调用本类的方法
}
} catch (Exception e) {
e.printStackTrace();
}
}
}.packageScan(packageName);
for (BeanMethodDefination beanMethod : beanMethodList) { //当包扫描完之后,将带有参数的方法继续产生代理
Class<?> returnType = beanMethod.getReturnType();
Parameter[] parameters = beanMethod.getParameters();
Object object = beanMethod.getObject();
Method method = beanMethod.getMethod();
String name = beanMethod.getNike();
try {
Object result = invokeLastMethod(proxyBeanFactory, object, parameters, method); //本类中的方法,后面讲到
createBean(proxyBeanFactory, returnType, result, name);
} catch (Exception e) {
e.printStackTrace();
}
}
}
private static void invokeBeanMethod(ProxyBeanFactory proxyBeanFactory, Object object,
Method method, List<BeanMethodDefination> beanMethodList) throws Exception{
Class<?> returnType = method.getReturnType(); //得到该类的返回类型
if (returnType.equals(void.class)) { //若返回值为void,则不处理
return;
}
Bean bean = method.getAnnotation(Bean.class);
String name = bean.name();
Parameter[] parameters = method.getParameters(); //得到该方法的参数
if (parameters.length <= 0) { //若没有参数,则直接反射,并创建一个代理加入beanMap
Object result = method.invoke(object);
createBean(proxyBeanFactory, returnType, result, name);
} else { //否则,先加入List<BeanMethodDefination>中
beanMethodList.add(new BeanMethodDefination(object, parameters,
returnType, name, method));
}
}
private static void createBean(ProxyBeanFactory proxyBeanFactory, Class<?> klass,
Object object, String name) throws Exception { //创建代理
if (object != null) {
proxyBeanFactory.creatCGLProxy(object);
} else {
proxyBeanFactory.creatCGLProxy(klass);
}
if (name.length() > 0) { //若name不为空值,则将该类的名称和该name加入beanNameMap中
proxyBeanFactory.addBeanNameMap(name, klass.getName());
}
}
private static Object invokeLastMethod(ProxyBeanFactory proxyBeanFactory, Object object,
Parameter[] parameters, Method method) throws Exception {
Object result = null;
int paraCount = parameters.length;
Object[] paras = new Object[paraCount];
for (int index = 0; index < paraCount; index++) {
Parameter parameter = parameters[index];
String klassName = parameter.getType().getName(); //得到参数类型的名称
SatProxy satProxy = proxyBeanFactory.getCGLProxy(klassName);//通过参数类型名称得到参数类型的代理
Object beanObject = satProxy.getObject(); //得到代理类的原对象
if (beanObject == null) {
continue;
}
paras[index] = beanObject;
}
result = method.invoke(object, paras); //通过代理原对象构成的参数进行反射得到方法的值
return result;
}
private static void injectBean(ProxyBeanFactory proxyBeanFactory, Class<?> klass,
Object object) {
Field[] fields = klass.getDeclaredFields(); //得到该类中的所有成员
SatProxy selfProxy = proxyBeanFactory.getCGLProxy(klass.getName());
selfProxy.setInjection(true); //将inJection改为true
for (Field field : fields) {
if (!field.isAnnotationPresent(Autowired.class)) { //若成员没有@Autowired注解
continue;
}
Class<?> fieldType = field.getType(); //得到成员的类型
SatProxy fieldProxy = proxyBeanFactory.getCGLProxy(fieldType.getName()); //得到成员类型的SatProxy
if (!fieldProxy.isInjection()) { //若成员类型没有注入,则递归调用本函数
injectBean(proxyBeanFactory, fieldType, object);
}
field.setAccessible(true); //设置该成员为可改
try {
field.set(object, fieldProxy.getObject()); //更改
} catch (Exception e) {
e.printStackTrace();
}
}
}
public static <T> T getProxyBeanFactory(Class<?> klass) { //指定类中注入成员
ProxyBeanFactory proxyBeanFactory = new ProxyBeanFactory();
SatProxy satProxy = proxyBeanFactory.getSatProxy(klass.getName());//指定类需要带@Conponent注解
if (!satProxy.isInjection()) { //若该类没有注入成员
injectBean(proxyBeanFactory, klass, satProxy.getObject());
}
T beanProxy = satProxy.getProxy();
return beanProxy; //得到代理
}
}
BeanMethodDefination类中有(Object、Method、Parameter[]、Class<?>(returnType)、String(name))以及get()和set()方法
上面提到@Component、@Bean、@Autowired注解,其中三个分别是在类、方法、成员中使用的注解。这里给出了一个注解,其余的注解只是Target不同
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Component {
String name() default "";
}
因为在扫描类或方法时是无序的,所以不能保证自己想用的类已经产生了代理。在BeanFactory类中扫描带方法的注解时,有的方法中可能含有参数,并且这个参数的类型在调用这个方法之前不确定是否已经产生代理,若参数类型没有产生代理就反射该方法就会产生异常。为了保证每次反射方法时都能正常执行,在BeanFactory类中扫描类中的方法时,如果该方法没有参数,就直接进行反射。如果有参数则先存入List中,等包中所有的类都扫描完之后,再将这个List中的每一个方法进行遍历并产生代理存入beanMap中。在此代码实现中规定如果方法的返回值类型为void,则不执行它。也就是说需要注入的方法不能没有返回值,并且返回值不能为八大基本类型。
在注入成员时,并不知道该成员的类是否已经注入。有时可能会出现a成员的A类没有注入,当注入A类时发现A类中依然有需要注入的b成员,当注入B类时又发现需要注入C类的c成员…(即循环依赖)在这种情况下,如果直接将a成员注入,则会抛出异常。为了解决这个问题,在执行该方法时进行判断,如果该成员的类已经注入,则直接注入该成员。如果没有注入,则继续调用BeanFactory类中的injectBean()方法(即递归调用)
前面讲的BeanFactory类主要是我实现IOC的核心代码。下面讲的IntercepterScanner类是我实现AOP(添加拦截器)的核心代码
public class IntercepterScanner {
public IntercepterScanner() {
}
public static void scanIntercepter(String packageName) { //扫描包
new PackageScanner() {
@Override
public void dealClass(Class<?> klass) {
if (!klass.isAnnotationPresent(Aspect.class)) { //@Aspect注解,return
return;
}
IntercepterFactory intercepterFactory = new IntercepterFactory(); //前面讲过IntercepterFactory类
try {
Object object = klass.newInstance();
Method[] methods = klass.getDeclaredMethods();
for (Method method : methods) { //遍历含有注解类中的方法
if (method.isAnnotationPresent(Before.class)) { //如果有@Before注解
Before before = method.getAnnotation(Before.class);
dealBeforeIntercepter(intercepterFactory, method, before, klass, object);
} else if (method.isAnnotationPresent(After.class)) { //如果有@After注解
After after = method.getAnnotation(After.class);
dealAfterIntercepter(intercepterFactory, method, after, klass, object);
} else if (method.isAnnotationPresent(ThrowsException.class)) { //如果有@Exception注解
ThrowsException exception = method.getAnnotation(ThrowsException.class);
dealExceptionIntercepter(intercepterFactory, method, exception, klass, object);
} else {
return;
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}.packageScan(packageName);
}
private static void dealBeforeIntercepter(IntercepterFactory intercepterFactory, Method method,
Before before, Class<?> klass, Object object) throws Exception{ //处理带有@Before注解的方法
Class<?> returnType = method.getReturnType();
if (returnType.equals(Boolean.class)) { //如果该方法的返回值类型不为Boolean,抛出异常
throw new BadReturnTypeException("方法(" + method + ")的返回值类型应为Boolean");
}
Class<?> targetKlass = before.klass(); //得到注解中传过来目标方法的类
Class<?>[] parameterTypes = method.getParameterTypes(); //得到注解中传过来的目标方法名称
Method targetMethod = targetKlass.getMethod(before.method(), parameterTypes); //得到注解中传过来的目标方法中参数类型
IntercepterMethodDefination intercepterMethod = new IntercepterMethodDefination(klass, method, object); //得到拦截方法
IntercepterTargetDefination intercepterTarget = new IntercepterTargetDefination(targetKlass, targetMethod); //得到拦截目标方法
intercepterFactory.addBeforeMap(intercepterTarget, intercepterMethod); //将得到的方法加入相应的拦截器Map
}
private static void dealAfterIntercepter(IntercepterFactory intercepterFactory, Method method,
After after, Class<?> klass, Object object) throws Exception { //处理带有@After注解的方法
Class<?>[] parameterTypes = after.parasType(); //得到目标方法中的参数类型
Class<?> returnType = method.getReturnType(); //得到拦截方法的返回值类型
Class<?> targetKlass = after.klass(); //得到目标方法的类
Method targetMethod = targetKlass.getMethod(after.method(), parameterTypes);//通过目标方法名称和参数类型反射得到目标方法
Class<?> targetReturnType = targetMethod.getReturnType(); //得到目标方法的返回值类型
if (!returnType.equals(targetReturnType)) { //如果目标方法的返回值类型与拦截方法的返回值类型不同时,抛出异常
throw new BadReturnTypeException("方法(" + method + ")的返回值类型应与目标方法返回值类型不一样");
}
IntercepterMethodDefination intercepterMethod = new IntercepterMethodDefination(klass, method, object); //得到拦截方法
IntercepterTargetDefination intercepterTarget = new IntercepterTargetDefination(targetKlass, targetMethod); //得到目标拦截方法
intercepterFactory.addAfterMap(intercepterTarget, intercepterMethod); //加入相应的Map
}
private static void dealExceptionIntercepter(IntercepterFactory intercepterFactory, Method method,
ThrowsException exception, Class<?> klass, Object object) throws Exception { //处理带有@Exception注解的方法,与前面的方法相似
Class<?> returnType = method.getReturnType();
if (returnType.equals(void.class)) {
throw new BadReturnTypeException("方法(" + method + ")的返回值类型应为void");
}
Class<?>[] parameterTypes = method.getParameterTypes();
if (parameterTypes.equals(new Class<?>[]{Throwable.class})) {
throw new BadParameterTypesException("方法(" + method + ")的参数类型不正确");
}
Class<?> targetKlass = exception.klass();
Method targetMethod = targetKlass.getMethod(exception.method(), parameterTypes);
IntercepterMethodDefination intercepterMethod = new IntercepterMethodDefination(klass, method, object);
IntercepterTargetDefination intercepterTarget = new IntercepterTargetDefination(targetKlass, targetMethod);
intercepterFactory.addExceptionMap(intercepterTarget, intercepterMethod);
}
}
上面类中提到@Before、@After、@Exception注解,这里给出@After的代码
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface After {
Class<?> klass();
String method();
Class<?>[] parasType() default {Class.class};
}
在@After注解中有目标方法的参数类型,其默认值为Class,这是为了通过目标方法的参数类型及方法名称反射出目标方法,并判断目标方法的返回值与拦截方法的返回值是否一致。若不一致,则要抛出异常。其他两个注解与@After相似,但是不需要参数类型,因为他们的拦截方法的返回值都已经确定。即Before拦截的方法的返回值为boolean,Exception拦截的方法无返回值