手動實現IOC與事務控制-JDBC-4-基於自定義註解

基於之前的添加pom文件

    <!--反射工具包-->
    <dependency>
      <groupId>org.reflections</groupId>
      <artifactId>reflections</artifactId>
      <version>0.9.12</version>
    </dependency>
    <!--工具包-->
    <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-lang3</artifactId>
      <version>3.10</version>
    </dependency>

配置文件

在這裏插入圖片描述
basePackage=com.liu

註解


/**
 * @Description 用於注入一個對象
 * @ClassName Autowired 類名
 * @Author 劉楠
 * @date 2020.06.30
 */
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {

    /**
     * 依賴必須存在,不然就報錯
     * @return
     */
    boolean required() default true; //true就必須注入
}

/**
 * @Description 用於標記一個類
 * @ClassName Service 類名
 * @Author 劉楠
 * @date 2020.06.30
 */
@Documented
@Target(ElementType.TYPE) //只能用在類上
@Retention(RetentionPolicy.RUNTIME)
public @interface Service {
    /**
     * 類的id名稱
     * @return
     */
    String value() default "";//可以有也可以沒有
}
@Target({ElementType.TYPE}) //類上
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Transactional {
    /**
     * 這個給個默認值也可以給空,工廠裏獲取也可以 這個省個事
     * @return
     */
    String value() default "transactionManager"; //默認事務管理器
}

在dao service TransactionManager ProxyFactory修改使用以上註解

  • dao
@Service("accountDao")
public class JdbcAccountDaoImpl implements AccountDao {

    @Autowired
    private ConnectionUtils connectionUtils;

  • service
@Service("transferService")
@Transactional
public class TransferServiceImpl implements TransferService {


    // 最佳狀態
    @Autowired
    private AccountDao accountDao;

  • TransactionManager
@Service("transactionManager")
public class TransactionManager {

    @Autowired
    private ConnectionUtils connectionUtils;

  • ProxyFactory
@Service("proxyFactory")
public class ProxyFactory {

    @Autowired
    private TransactionManager transactionManager;

    public void setTransactionManager(TransactionManager transactionManager) {
        this.transactionManager = transactionManager;
    }

新增一個工具類

public class PropertiesUtils {
    private static Properties props = new Properties();
    public static Properties getProperties(String path) {

        InputStream in = PropertiesUtils.class.getClassLoader().getResourceAsStream(path);
        try {
            props.load(in);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return props;
    }


}

修改 BeanFactory原來改名BeanFactoryOld不用,新建BeanFactory

public class BeanFactory {


    private static Map<String, Object> map = new ConcurrentHashMap<>();  // 存儲對象
    //默認要掃描的包,可通過配置文件來 如果配置文件中爲空就使用這個
    private static String basePackage = "com.liu";
    private static String basePackageKey = "basePackage";

    static {


        try {

            /**
             * 1.掃描指定包下的所有類,獲取指定註解的類的集合
             * 2.使用反射創建對象
             * 3.獲取Service注射標記的類
             * 4.判斷註解value是否有值,有就放入容器
             * 5.無值 如果有是類就獲取類名稱,並放入容器
             * 6.無值情況下獲取接口的名稱,如果無值同時接口數量大於1就拋出異常
             * 7.無值只有一個接口,獲取接口名稱放入容器
             * 8.初始化完成
             */
            doInitializationBean();

            /**
             * 判斷是否有Autowired,
             */
            doAutowired();
            /**
             * Transactional註解標記的類
             */
            doTransactional();

        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }

    }




    /**
     * 初始化Bean,並放入容器中
     * @throws InstantiationException
     * @throws IllegalAccessException
     */
    private static void doInitializationBean() throws InstantiationException, IllegalAccessException {
        //1.加載配置因爲文件
        Properties properties = PropertiesUtils.getProperties("base.properties");
        String property = properties.getProperty(basePackageKey);
        //如果配置文件中沒有,就用默認的
        if (StringUtils.isBlank(property)) {
            property = basePackage;
        }
        //2.使用反射工具類獲取所有帶Service註解的類
        Reflections reflections = new Reflections(property);
        //獲取所有Service註解的類
        Set<Class<?>> classSet = reflections.getTypesAnnotatedWith(Service.class);
        //3. 通過反射實實例化
        for (Class<?> clazz : classSet) {

            //實例化通過無參數構造
            Object newInstance = clazz.newInstance();
            //獲取註解
            Service annotation = clazz.getAnnotation(Service.class);
            //獲取註解中的值
            if(StringUtils.isBlank(annotation.value())) { //註解沒有值
                //獲取接口類
                Class<?>[] interfaces = clazz.getInterfaces();
                if (interfaces.length > 1) { //判斷接口數量是否>1
                    throw new RuntimeException("該有多個父接口,並沒有指定名稱,請使用Service註解指定名稱");
                }
                if (interfaces.length == 0) { //接口數量爲0,沒有接口
                    //沒有接口就是個類獲取類名稱
                    String simpleName = clazz.getSimpleName();
                    //首字母小寫
                    String key = StringUtils.uncapitalize(simpleName);
                    //放入容器中
                    map.put(key,newInstance);

                } else {
                    //接口數量爲1
                    //接口名稱
                    String simpleName = interfaces[0].getSimpleName();
                    //首字母小寫
                    String key = StringUtils.uncapitalize(simpleName);
                    //放入容器中
                    map.put(key,newInstance);
                }
            }else {
                //註解中有值
                //4.將類放入容器中
                String id = annotation.value();
                //首字母小寫
                String key = StringUtils.uncapitalize(id);
                //放入容器中
                map.put(key,newInstance);
            }
        }
    }

    /**
     * 注入
     */
    private static void doAutowired() {
       try {
           //從容器中獲取循環判斷
           for(Map.Entry<String,Object> entry:map.entrySet()){
               //1.獲取創建的對象
               String objKey = entry.getKey();
               Object value = entry.getValue();
               //2.獲取對象的類
               Class clazz =value.getClass();
               //獲取所有屬性字段
               Field[] fields = clazz.getDeclaredFields();
               //循環處理
               for (Field field : fields) {
                   //3.判斷是否有Autowired註解
                   if(field.isAnnotationPresent(Autowired.class)&& field.getAnnotation(Autowired.class).required()){
                       //4.如果是有Autowired並且值是true,就從容器中去獲取對象
                       String simpleName = field.getType().getSimpleName();
                       //5.將首字母小寫
                       String key = StringUtils.uncapitalize(simpleName);
                       //獲取要注入的對象
                       Object o = map.get(key);
                       //沒有就異常
                       if(o==null){
                           throw new RuntimeException(simpleName+"依賴的對象不存在 是null");
                       }
                       //獲取這個類的方法
                       Method[] methods = clazz.getMethods();
                       for (Method method : methods) {
                           //6.找到對應字段set方法
                           if(method.getName().equalsIgnoreCase("set"+simpleName)){
                               //7.執行setter方法賦值
                               method.invoke(value, o);
                           }
                       }
                   }
               }


               /**
                * 爲什麼不在這裏做事務,因爲事務代理工廠,也需要注入,可能沒有完成初始完成,放在下一輪中都實例和注入完成後,再代理
                * public class ProxyFactory {
                *
                *     @Autowired
                *     private TransactionManager transactionManager;
                */

               //8.重新放入容器中
               map.put(objKey, value);
           }

       } catch (IllegalAccessException e) {
           e.printStackTrace();
       } catch (InvocationTargetException e) {
           e.printStackTrace();
       }

    }
    /**
     * 事務代理
     */
    private static void doTransactional() {
        for(Map.Entry<String,Object> entry:map.entrySet()) {

            //1.獲取創建的對象
            String key = entry.getKey();
            Object value = entry.getValue();
            //2.獲取屬性
            Class clazz = value.getClass();
            //3.判斷當前對象的類是否有Transactional
            if(clazz.isAnnotationPresent(Transactional.class)){
                //4.有這個註解說明要開啓事務,獲取代理工廠
                ProxyFactory proxyFactory = BeanFactory.getBean("proxyFactory", ProxyFactory.class);
                //5.判斷 這個對像是否有實現接口
                Object proxyObj=null;
                Class[] interfaces = clazz.getInterfaces();
                //判斷有沒有接口
                if(interfaces!=null&&interfaces.length>0){
                    //6.有接口使用jdk
                    proxyObj = proxyFactory.getJdkProxy(value);
                }else{
                    //7.就是個類使用cglib
                    proxyObj = proxyFactory.getCglibProxy(value);
                }

                //8.重新放入容器中 將代理對象放入
                map.put(key, proxyObj);
                //10.完成代理
            }
        }
    }


    public static  Object getBean(String id) {
        return map.get(id);
    }
    public static  <T> T getBean(String id,Class<T> clazz) {
        return (T)map.get(id);
    }

}

修改servlet


public class TransferServlet extends HttpServlet {

    /**
     * 通過工廠獲取Service
     */
    private TransferService transferService = BeanFactory.getBean("transferService",TransferService.class) ;

修改完成

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章