Java通过注解实现简单SpringIOC及cglib动态代理

一.需要的maven依赖

<!--cglib动态代理-->
<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib-nodep</artifactId>
    <version>3.3.0</version>
</dependency>

<!--包扫描工具,用于寻找注解-->
<dependency>
    <groupId>org.reflections</groupId>
    <artifactId>reflections</artifactId>
    <version>0.9.11</version>
</dependency>

二.ioc及cglib实现代码

1.autowired注解,用于成员变量属性注入

package com.xy.ioc;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 标有这个注解的变量将会被注入相对应的对象
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoWired {

    /**
     * 当前注入对象的类型
     */
    Class <?> classes ();
}

classes为当前要注入的实现类,这么写流程更简单,不用进行复杂的逻辑判断,也不会出现依赖注入失败的问题

如:

@AutoWired(classes = UserServiceImpl.class)
private UserService userServiceImpl;

2.component注解,指定类存入bean管理容器中

package com.xy.ioc;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 标有该注解的类会在IoC容器中产生相对应的对象
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Component {

}

 3.packageScan注解,扫描指定包目录,用于反射bean对象

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 注解扫描
 * 扫描value中的包下的所有注解
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface PackageScan {
    String value() default "";
}

 4.bean管理容器,用于存储反射生成的bean代理对象

import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * IoC容器
 */
public class ApplicationContext {
    /**
     * 装有 [类名 : 类对应的实例] 的容器
     */
    private Map<String, Object> objectMap;

    /**
     * 初始化map
     */
    protected ApplicationContext() {

      this.objectMap = new ConcurrentHashMap<>();

    }

    /**
     * 添加类,并创建相应的实例对象到map容器中
     *
     * @param clazz 所添加的类对象
     */
    protected <T> void push(Class<T> clazz) {
        try {
            //创建动态代理类
            T proxy = CglibProxyFactory.getProxy(clazz);
            if(proxy!=null){
                //将代理类存入map容器中
                this.objectMap.put(clazz.getSimpleName(), proxy);
            }else{
                this.objectMap.put(clazz.getSimpleName(), clazz.newInstance());
            }


        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 获取类所继承的接口
     *
     * @param clazz 通过类实例反射来所获取类所继承的的接口
     * @return 所获取的类所继承的接口
     */
    public <T> T getObject(Class<T> clazz) {
        return (T) this.getObjectMap().get(clazz.getSimpleName());
    }


    /**
     * 获取map容器键的集合
     *
     * @return 获取所有键值对
     */
    protected Set<String> classSet() {
        return this.objectMap.keySet();
    }


    public Map<String, Object> getObjectMap() {
        return this.objectMap;
    }


    /**
     * 单例模式
     */
    private static ApplicationContext instance;

    public static ApplicationContext getInstance() {
        if (instance == null) {
            instance = new ApplicationContext();
        }
        return instance;
    }

}

5.ioc功能实现

package com.xy.ioc.implement;

import com.xy.exception.AttributeInjectionException;
import com.xy.exception.HasNoBeanException;
import com.xy.ioc.AutoWired;
import com.xy.ioc.Component;
import com.xy.ioc.PackageScan;
import org.reflections.Reflections;

import java.lang.reflect.Field;
import java.util.Set;

/**
 * IOC 功能实现
 */
public class MyApplication {


    private static MyApplication application;

    protected ApplicationContext applicationContext;

    /**
     * 初始化bean容器
     */
    public MyApplication() {
        this.applicationContext = ApplicationContext.getInstance();
    }


    /**
     * 通过run方法初始化当前类及bean容器,同时启动bean容器
     * @param clazz 启动类
     */
    public static MyApplication run(Class<?> clazz) {
        if (application == null) {
            application = new MyApplication();
        }
        if (clazz != null) {
            application.scan(clazz);
        }
        return application;
    }

    /**
     * 获取启动类包扫描注解,进行包扫描
     * @param clazz 启动类
     */
    public void scan(Class<?> clazz) {
        //获取scan注解,得到扫描包范围
        PackageScan PackageScan = clazz.getAnnotation(PackageScan.class);

        //从注解中获取包名
        String scanValue = PackageScan.value();


        //如果value等于空字符串,获取启动类包路径
        if ("".equals(scanValue)) {
            scanValue = clazz.getPackage().getName();
        }

        //初始化扫描器
        Reflections ref = new Reflections(scanValue);

        // 获取包下所有有component注解的对象的bean对象
        Set<Class<?>> classSet = ref.getTypesAnnotatedWith(Component.class);

        //初始化ioc容器
        init(classSet);
    }

    /**
     * 初始化容器, 将含有component的类存入容器中
     */
    private void init(Set<Class<?>> classSet) {

        //获取含有Competent注解的类存入map容器
        for (Class<?> aClass : classSet) {
            try {
                applicationContext.push(aClass);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
        //获取含有AutoWired注解的属性类,注入含有Competent类中
        for (Class<?> aClass : classSet) {
            try {
                injectionObject(aClass);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }


    /**
     * 将容器中的实例中标记有@AutoWired注解的属性注入相应的对象
     */
    private void injectionObject(Class<?> aClass) {

        //获取当前类成员属性
        Field[] fields = aClass.getDeclaredFields();

        //获取类示例
        Object clazzObject = applicationContext.getObject(aClass);
        for (Field field : fields) {

            //初始化属性上的AutoWired注解
            AutoWired autoWired = field.getAnnotation(AutoWired.class);

            //判断属性上是否存在注解
            if (autoWired != null) {

                //判断容器中是否存在成员属性类
                if (applicationContext.getObject(autoWired.classes()) == null) {
                    throw new HasNoBeanException("bean容器不存在指定的bean对象,请检查注入类对象上是否包含@Component注解");
                }

                try {
                    //开启访问
                    field.setAccessible(true);

                    //获取注入的属性类
                    Object fieldObject = applicationContext.getObject(autoWired.classes());

                    //将类注入属性
                    field.set(clazzObject, fieldObject);
                } catch (Exception e) {
                    throw new AttributeInjectionException("注入属性失败");
                }
            }
        }
    }
}

1. MyApplication():实例化bean容器

 2.run(Class<?> clazz) :ioc容器启动方法

 3.scan(Class<?> clazz):扫描包路径,寻找含有component的bean对象

 4.init(Set<Class<?>> classSet):将bean对象存入bean容器,并进行成员变量属性注入

 5.injectionObject(Class<?> clazz):寻找当前类是否包含autowired,如果有则注入

6.cglib动态代理

package com.xy.ioc.implement;


import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * 业务代理工厂类
 *
 * 需要方法增强的类使用cglib代理
 *
 * jdk11以上添加vm启动参数(重要) :--add-opens java.base/java.lang=net.sf.cglib --add-opens java.base/sun.net.util=net.sf.cglib
 *
 *   代理类包路径需要在module-info.java中开放访问,否则会报异常
 */


public class CglibProxyFactory {


    /**
     * 获取代理对象
     *
     * @param clazz
     * @return
     */
    @SuppressWarnings("unchecked")
    public static  <T> T getProxy(Class<T> clazz) {

        //创建增强器对象
        Enhancer enhancer = new Enhancer();
        //为将要生成的代理对象设置父类
        enhancer.setSuperclass(clazz);



        //设置代理对象调用业务方法时的统一处理  Ctrl+H 查看类的继承体系结构
        enhancer.setCallback(new MethodInterceptor() {
            /**
             * 通过代理对象对所有业务方法的统一处理
             *
             * @param proxy       代理对象
             * @param method      代理对象调用的方法
             * @param args        方法的参数
             * @param methodProxy 方法代理对象
             * @return 代理方法的返回值
             * @throws Throwable
             */
            public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                Object returnVal = null;
                try {
                   
                    //通过代理对象调用它的父类被重写的真实方法
                    returnVal = methodProxy.invokeSuper(proxy, args);


                 
                } catch (Exception e) {
                     throw e; //将业务层异常抛到表示层
                } finally {
                    //System.out.println("最终");
                }
                return returnVal;
            }
        });
        //生成代理对象
        return  (T) enhancer.create();
    }


    
}

cglib动态代理,用于方法使用时前后增强,高版本jdk需module.info中在开放依赖类包目录访问,以及添加vm启动参数,否则或出现异常:

  --add-opens java.base/java.lang=net.sf.cglib

  --add-opens  java.base/sun.net.util=net.sf.cglib

 7.需要依赖注入的类

package com.xy.controller;


import com.xy.ioc.AutoWired;
import com.xy.ioc.Component;
import com.xy.manager.ContextManager;
import com.xy.service.UserService;
import com.xy.service.impl.UserServiceImpl;

@Component
public class MainController {

    @AutoWired(classes = UserServiceImpl.class)
    private UserService userServiceImpl;

    @AutoWired(classes = ContextManager.class)
    private ContextManager contextManager;



    public void get(){
       userServiceImpl.hello();
        contextManager.print();

    }


    public UserService getUserService() {
        return this.userServiceImpl;
    }
}



测试的controller类

8.注入的接口

package com.xy.service;

public interface UserService {
    void hello();
}

9.接口实现类

package com.xy.service.impl;

import com.xy.ioc.Component;
import com.xy.service.UserService;

@Component
public class UserServiceImpl implements UserService {
    @Override
    public void hello() {
        System.out.println("加班中");
    }
}

接口及接口实现类

10.启动类

package com.xy;


import com.xy.controller.MainController;
import com.xy.ioc.PackageScan;
import com.xy.ioc.implement.ApplicationContext;
import com.xy.ioc.implement.MyApplication;



@PackageScan("com.xy")
public class MainApplication {
    
    public static void main(String[] args) throws Exception {
       MyApplication.run(MainApplication.class);
       MainController object = ApplicationContext.getInstance().getObject(MainController.class);
        object.get();
    }
    

}

1.MyApplication.run启动ioc容器,参数为当前main方法启动类;

2.package(指定路径会去扫指定路径下的目录,没有指定会去扫描main方法启动类的包目录)注解会去扫描包路径下含有componet注解的bean对象

3.将含有注解的类反射生成cglib动态代理后将其注入bean容器中

4.将含有autowired注解的成员变量注入类属性

5.直接调用(和spring一样)

三.运行结果

四.总结

代码功能比较简单,没有使用三级缓存解决循环依赖的问题,关于这个问题,我的看法是在实际的开发过程中尽量避免出现循环依赖的问题。还有新版spring已不再解决循环依赖问题了。代码还有很多不足,如有不正之处,欢迎在评论区指正,共同进步 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值