手写Spring

最近我手写实现了Spring的核心功能,通过手写更深入理解点击打开链接了反射/动态代理

Spring核心包括两部分:AOP/IOC


完整代码可以去我的GitHub

点击打开链接



介绍AOP和IOC之前,先 看看动态代理和反射


代理是一种设计模式,假如我们要找媳妇,我们可以不用自己去找,可以去婚姻介绍所,

婚姻介绍所就是代理,他可以帮我们找到需要的对象.当然了,在得到对象之前,我们需要告诉他需要那个,他会给我们看照片吧,看对象的介绍,然后我们看上哪个了就得到了(假设),在得到后,介绍所会收取一定费用(使用动态代理对方法进行增强).

关于动态代理,我们可以用jdk自带的(需要接口来生成代理类)

需要写一个类实现InvocationHandler接口

然后实现invoke方法,当我们使用代理类调用里面的方法时,会走这个方法,这里我们


我们在构造里接受参数 c 就是需要被代理的对象

public JdkInvocationHandler(Object c){
    this.c=c;
}

然后可以在调用被代理对象的方法之前输出"之前" ,然后在执行代理类方法后输出"之后"

这就是动态代理的好处,可以对方法进行增强

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
   
System.out.println("之前");
//这里第一个参数必须是Object---------------------- method.invoke( c ,args) ;
System.out.println("之后");
return proxy ;}

然后我们可以这样获得代理类


JdkInvocationHandler jdkInvocationHandler=new JdkInvocationHandler(c.newInstance());

Object o = Proxy.newProxyInstance(jdkInvocationHandler.getClass().getClassLoader(), c.getInterfaces(), jdkInvocationHandler);

先创建一个实现了InvocationHandler接口的类,传入一个需要代理的对象

然后通过Proxy.newInstance()方法,传递一个类加载器,接口,实现了InvocationHandler接口的类来生成代理类

然后我们就能使用这个代理类了

可以对他进行强转,然后调用方法就能看见效果了


**jdk的动态代理是有弊端的,那就是只能使用接口来生成代理类

假如我们需要代理的对象没有实现接口怎么办

这时候我们可以用cglib,可以通过继承的办法来生成代理类

-------

和jdk的动态代理差不多,我们需要写一个实现了Methodinterceptor接口的类

执行被代理类的方法前打印“之前”,执行后打印“之后”

public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {

    System.out.println("之前");
   
    methodProxy.invokeSuper(o,objects);
    
System.out.println("之后");
return o ;}


怎么获得对象呢,先创建一个增强器,然后设置回调(就是调用代理类的方法需要做的事),然后create就得到对象了


Enhancer enhancer = new Enhancer();
enhancer.setCallbacks(new Callback[]{new CGlibMethodInterceptor(listListEntry.getKey(), listListEntry.getValue())});
enhancer.setSuperclass(c);
Object o = enhancer.create();
强转后就能直接调用了



----------

接下来是关于反射的

我们可以通过Class.forName(String className)来传入类名来获得类对象

可以理解成数据库的select操作,通过类名查找Class

可以用Method.invoke(Object o,Object[] args)来调用指定对象里面的方法

可以用Field.set(Object o,Object v) 来设置类里面的字段值

----------------------

AOP

面向切面编程,可以让我们专注于业务逻辑开发(用动态代理实现)

具体可以看这个

AOP详解

使用动态代理来对方法进行增强

-----------------------

IOC

控制反转(用反射实现)

可以让框架来管理类

让类的创建交给框架处理,

比如我们获得通过反射获得一个类对象,然后需要对类进行初始化,并且要对加了@Autowired注解的字段进行设置值,我们就把对字段的设置交给了框架进行处理,就实现了控制反转

还有对需要增强方法的类进行增强,通过动态代理来生成代理类,也实现了控制反转



接下来我们看一下关于AOP和IOC的具体流程(纯手写,仅实现核心功能)


1.首先,我们需要定义注解

After/Aspect/Autofired/BackPackage/Before/Controller/RequestMapping/Service




2.然后写一个DispatcherServlet(核心)

并在web.xml中配置这个Servlet



当我们访问任意路径, 都会调用这个servleet来执行

这个Servlet有个init方法,会在初始化的时候执行

我们可以在init方法中写初始化"框架"的方法

1.获得需要扫描的包名



2.然后通过递归扫描指定包下的所有类,放到容器里



3.接下来就是初始化切面容器,我们需要将条件和之前/之后需要调用的方法和类对象放到容器里

由于我们切面是这样使用的,之前要执行的方法可以有很多个,之后要执行的方法可能也有很多个

这里我们可以把他放到Map中


这样放到map中,用于后面为需要增强方法的对象通过动态代理进行增强




4.然后我们需要对类进行初始化

    逻辑是:

            遍历放了所有类的容器

                     如果类全名在切面容器内出现了

                            判断这个类时候实现了接口

                             如果实现了接口,就使用jdk动态代理,将切面容器中的之前之后方法传到jdkInvocationHandler中,生成代理对象并放到容器里用于后面对使用了Autowired注解的字段进行注入

                            如果没有实现接口,就使用cglib生成代理对象并放大容器里,用于后面注入

                        如果没有在切面容器里出现,就直接newInstance 放到容器里后面再注入

5.然后我们需要遍历容器里面存放的对象引用

遍历对象引用,并且遍历所有字段,如果加了Autowired注解,就从instanceMap中拿到并通过反射来注入值

通过Field.set(Object o,Object v)方法





6.然后我们需要扫描所有Controller

获得所有映射和方法/类放到容器里



7.然后在doGet和doPost中写方法处理请求




这个方法就是获得请求,然后在url映射容器里找需要执行的方法,和类,然后通过反射进行调用

如果返回了String 就表示要显示jsp页面,就直接forword



Mybatis的手写核心功能也完成了,明天写博客,睡觉


完整代码可以去我的GitHub

 点击打开链接

猜你喜欢

转载自blog.csdn.net/u011546032/article/details/80787768