自定义控制反转自动注入示例

本实例主要是学习java反射和JDBC的相关内容。本实例涉及到的内容没有用完并且代码健壮性比较差,可扩展性还有很多。该实例适用于maven/gradle项目,并且使用mysql8.0。普通项目记得修改扫描目录。

1. 定义四个注解类

(1)AutoWired作用于属性,标记注入属性


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 {

}


(2)DaoResource作用于接口,表示这是一个jdbc操作接口



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

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface DaoResource {

}

(3) Field作用于属性,表示这是一个数据库字段



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 Field {

}

(4)Table 作用于类,表示这是一个实体类,对应数据库表



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

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Table {

}

2. 定义BaseDao接口,模拟Mybatis plus的Mapper接口


import java.sql.SQLException;

public interface BaseDao<T> 
{
  public void create(T entity) throws SQLException;
  public void deleteById(Long id) throws SQLException;
  public void insert(T entity) throws SQLException;
  public T selectById(Long id) throws SQLException;
  public void update(T entity) throws SQLException;
}

3. 定义JdbcUtils类,对数据库的基本操作。

import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

// 不适用并发
public class JdbcUtils
{
   private String url = "jdbc:mysql://localhost:3306/test?characterEncoding=utf8&allowPublicKeyRetrieval=true&useSSL=false";
   private String user = "root";
   private String password = "root";

   static
   {
      try
      {
         String driver = "com.mysql.cj.jdbc.Driver";
         Class.forName(driver);
      }
      catch (ClassNotFoundException e)
      {
         e.printStackTrace();
      }
   }

   public synchronized Connection getConnection() throws SQLException
   {

      Connection connection = DriverManager.getConnection(url, user, password);
      connection.setAutoCommit(false);
      return connection;
   }

   public void deleteById(Class<?> entityClass, Long id) throws SQLException
   {
      String tableName = entityClass.getSimpleName();
      String sql = "delete from " + tableName + " where id=" + id;
      System.out.println(sql);
      execute(sql);
   }

   public void insert(Object entity) throws SQLException
   {
      StringBuilder sql = new StringBuilder();
      StringBuilder sqlFields = new StringBuilder();
      StringBuilder sqlValues = new StringBuilder();

      Class<?> clazz = entity.getClass();
      String tableName = clazz.getSimpleName();
      Field[] fields = clazz.getDeclaredFields();
      sql.append("insert into ").append(tableName);
      sqlFields.append(" (");
      sqlValues.append(" (");
      for (Field field : fields)
      {
         try
         {
            field.setAccessible(true);
            Object value = field.get(entity);
            String type = field.getGenericType().getTypeName();
            if (type == "id" && value == null)
            {
               throw new RuntimeException("id 不能为空");
            }

            switch (type)
            {
            case "java.lang.String":
               sqlFields.append(field.getName());
               sqlValues.append(value == null ? null : "'" + value + "'");
               break;
            case "java.lang.Integer":
               sqlFields.append(field.getName());
               sqlValues.append(value);
               break;
            default:
               break;
            }
            sqlFields.append(",");
            sqlValues.append(",");
         }
         catch (IllegalArgumentException | IllegalAccessException e)
         {
            e.printStackTrace();
         }
      }
      System.out.println(sqlFields.toString());
      System.out.println(sqlValues.toString());
      sqlFields.replace(sqlFields.lastIndexOf(","), sqlFields.length(), ") ");
      sqlValues.replace(sqlValues.lastIndexOf(","), sqlValues.length(), ") ");
      sql.append(sqlFields).append(" value ").append(sqlValues);
      System.out.println(sql);
      execute(sql.toString());
   }

   @SuppressWarnings("deprecation")
   public Object selectById(Class<?> entityClass, Long id) throws SQLException
   {
      String tableName = entityClass.getSimpleName();
      String sql = "select * from " + tableName + " where id=" + id;
      System.out.println(sql);

      {
         try (Connection connection = getConnection(); Statement statement = connection.createStatement();)
         {
            ResultSet rs = statement.executeQuery(sql.toUpperCase());
            if (rs.next())
            {
               Field[] fields = entityClass.getDeclaredFields();
               Object result = entityClass.newInstance();
               for (Field field : fields)
               {
                  field.setAccessible(true);
                  Object value = rs.getObject(field.getName());

                  field.set(result, value);
               }
               return result;
            }
         }
         catch (Exception e)
         {
            e.printStackTrace();
         }
      }
      return null;
   }

   public void update(Object entity) throws SQLException
   {
      StringBuilder sql = new StringBuilder();
      Class<?> clazz = entity.getClass();
      String tableName = clazz.getSimpleName();
      Field[] fields = clazz.getDeclaredFields();
      sql.append("update ").append(tableName).append(" set ");
      for (Field field : fields)
      {
         try
         {
            field.setAccessible(true);
            Object value = field.get(entity);
            String type = field.getGenericType().getTypeName();
            if (field.getName().toLowerCase() != "id" && field.get(entity) != null)
            {
               switch (type)
               {
               case "java.lang.String":
                  sql.append(field.getName() + "='" + value + "'");
                  break;
               case "java.lang.Integer":
                  sql.append(field.getName() + "=" + value);
                  break;
               default:
                  break;
               }
               sql.append(",");
            }
         }
         catch (IllegalArgumentException | IllegalAccessException e)
         {
            e.printStackTrace();
         }
      }

      try
      {
         Field field = clazz.getDeclaredField("id");
         field.setAccessible(true);
         Object id = field.get(entity);
         sql.delete(sql.length() - 1, sql.length());
         sql.append(" where id=" + id);
      }
      catch (Exception e)
      {
         e.printStackTrace();
      }
      System.out.println(sql.toString());
      execute(sql.toString());
   }

   public void createTable(Object entity) throws SQLException
   {
      StringBuilder sql = new StringBuilder();
      Class<?> clazz = entity.getClass();
      String tableName = clazz.getSimpleName();
      Field[] fields = clazz.getDeclaredFields();
      sql.append("CREATE TABLE ");
      sql.append(tableName);
      sql.append("( ");
      for (Field field : fields)
      {
         field.setAccessible(true);
         try
         {
            String fieldName = field.getName();
            String type = field.getGenericType().getTypeName();
            switch (type)
            {
            case "java.lang.String":
               sql.append(fieldName + " VARCHAR(100),");
               break;
            case "java.lang.Integer":
               sql.append(fieldName + " int ,");
               break;
            default:
               break;
            }
         }
         catch (IllegalArgumentException e)
         {
            e.printStackTrace();
         }
      }
      sql.delete(sql.length() - 1, sql.length());
      sql.append(" ) DEFAULT CHARSET=utf8;");
      String sqlStr = sql.toString().toUpperCase();
      if (!sqlStr.contains("EXISTS"))
      {
         if (!tableExists(tableName))
         {
            execute(sqlStr);
         }
      }
   }

   private void execute(String sql)
   {
      try (Connection connection = getConnection(); Statement statement = connection.createStatement();)
      {
         statement.execute(sql.toUpperCase());
         connection.commit();
      }
      catch (Exception e)
      {
         e.printStackTrace();
      }
   }

   private Boolean tableExists(String tableName) throws SQLException
   {

      int numRows = 0;
      try (Connection connection = getConnection();
         ResultSet resultSet = connection.getMetaData().getTables(null, null, tableName.toUpperCase(), null);)
      {
         while (resultSet.next())
            ++numRows;
      }
      catch (Exception e)
      {
         e.printStackTrace();
      }
      return numRows > 0;
   }

   public void close(Connection connection, Statement statement, ResultSet resultSet)
   {
      try
      {
         if (connection != null)
         {
            connection.close();
         }
         if (statement != null)
         {
            statement.close();
         }
         if (resultSet != null)
         {
            resultSet.close();
         }
      }
      catch (Exception e)
      {
         e.printStackTrace();
      }
   }
}

4. 定义Person类对上述工具类可以做相关测试
 

@Table 
public class Person
{
   @Field 
   private Integer id;
   @Field
   private String name;
   @Field
   private Integer age;

   public Person()
   {
      
   }
  
   public Person(Integer id, String name, Integer age)
   {
      super();
      this.id = id;
      this.name = name;
      this.age = age;
   }

   public Integer getId()
   {
      return id;
   }

   public void setId(Integer id)
   {
      this.id = id;
   }

   public String getName()
   {
      return name;
   }

   public void setName(String name)
   {
      this.name = name;
   }

   public Integer getAge()
   {
      return age;
   }

   public void setAge(Integer age)
   {
      this.age = age;
   }

   @Override
   public String toString()
   {
      return "Person [id=" + id + ", name=" + name + ", age=" + age + "]";
   }

}

5. 定义PersonDao接口并继承BaseDao,这里模仿MyBatis plus的使用方法。


import java.sql.SQLException;
@DaoResource
public interface PersonDao extends BaseDao<Person>
{
   public void deleteByName(Long id) throws SQLException;
}

6. Application类是对整个应用进行控制的核心类。

import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Proxy;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
 
public class Application
{
   // system
   private String packagePath = System.getProperty("user.dir") + File.separator + "src" + File.separator
      + "main" + File.separator + "java" + File.separator;
   private Map<Class<?>, Object> instancedClasses = new HashMap<>();
   private List<Class<?>> classes = new ArrayList<>();
   private List<Class<?>> baseDaoClasses = new ArrayList<>();
   private List<Class<?>> entityClasses = new ArrayList<>();
   private static Application application = new Application();
   @AutoWired
   private JdbcUtils jdbcUtils;

   public static Application run()
   {
      try
      {
         application.init();
      }
      catch (Exception e)
      {
         e.printStackTrace();
      }
      return application;
   }

   // 反射操作
   public void init() throws Exception
   {
      instancedClasses.put(this.getClass(), application);
      instancedClasses.put(JdbcUtils.class, new JdbcUtils());
      String basePackage = "com._jdbc_03";
      File file = new File(packagePath + basePackage.replace(".", File.separator));
      loadClasses(file);
      parserBaseDaoClasses();
      parserAutoWiredFields();
 
   }

   @SuppressWarnings("deprecation")
   private void parserAutoWiredFields()
      throws IllegalArgumentException, IllegalAccessException, InstantiationException, ClassNotFoundException
   {
      for (Class<?> clazz : classes)
      {
         Object result = instancedClasses.get(clazz);
         if (result == null && !clazz.isInterface())
         {
            result = clazz.newInstance();
            instancedClasses.put(clazz, result);
         }
         Field[] fields = clazz.getDeclaredFields();
         for (Field field : fields)
         {
            field.setAccessible(true);
            if (field.isAnnotationPresent(AutoWired.class))
            {
               System.out.println(field.getType());
               Object object = instancedClasses.get(field.getType());
               System.out.println(object);
               if (object != null)
               {
                  System.out.println("获取不为空");
                  field.set(result, object);
               }
               else
               {
                  //field.set(object,field.getType().newInstance());
                  System.out.println("获取为空");
               }
            }
         }
      }
   }

   // https://www.jb51.net/article/124178.htm
   private void parserBaseDaoClasses()
   {
      for (Class<?> clazz : baseDaoClasses)
      {
         Object object = Proxy
            .newProxyInstance(clazz.getClassLoader(), new Class[] { clazz }, new InvocationHandler()
            {
               @Override
               public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
               {
                  if (Object.class.equals(method.getDeclaringClass()))
                  {
                     return method.invoke(this, args);
                  }
                  else
                  {
                     String methodName = method.getName();
                     switch (methodName)
                     {
                     case "create":
                        jdbcUtils.createTable(args[0]);
                        break;
                     case "insert":
                        jdbcUtils.insert(args[0]);
                        break;
                     case "selectById":
                     {
                        Type[] genericInterfaces = clazz.getGenericInterfaces();
                        for (Type genericInterface : genericInterfaces)
                        {
                           Type rawType = ((ParameterizedType) genericInterface).getRawType();
                           Class<?> interfaceType = (Class<?>) rawType;
                           if (interfaceType == BaseDao.class)
                           {
                              Type[] types = ((ParameterizedType) genericInterface).getActualTypeArguments();
                              Class<?> entityClass = (Class<?>) types[0];
                              return jdbcUtils.selectById(entityClass, (Long) args[0]);
                           }
                        }
                     }
                        break;
                     case "update":
                        jdbcUtils.update(args[0]);
                        break;
                     case "deleteById":
                     {
                        Type[] genericInterfaces = clazz.getGenericInterfaces();
                        for (Type genericInterface : genericInterfaces)
                        {
                           Type rawType = ((ParameterizedType) genericInterface).getRawType();
                           Class<?> interfaceType = (Class<?>) rawType;
                           if (interfaceType == BaseDao.class)
                           {
                              Type[] types = ((ParameterizedType) genericInterface).getActualTypeArguments();
                              Class<?> entityClass = (Class<?>) types[0];
                              jdbcUtils.deleteById(entityClass, (Long) args[0]);
                           }
                        }

                     }
                        break;
                     default:
                        // other
                        break;
                     }
                  }
                  return null;
               }
            });
         instancedClasses.put(clazz, object);
      }
   }

   public Object getClass(Class<?> clazz)
   {
      return instancedClasses.get(clazz);
   }

   // 加载所有类
   private void loadClasses(File file) throws ClassNotFoundException
   {
      if (file.exists())
      {
         File[] files = file.listFiles();
         if (null != files && files.length > 0)
         {
            for (File f : files)
            {
               if (f.isFile() && f.getName().endsWith(".java"))
               {
                  String filePath = f.getAbsolutePath();
                  String qualifiedName = filePath
                     .substring(packagePath.length(), filePath.length() - 5)
                     .replace(File.separator, ".");
                  Class<?> clazz = Class.forName(qualifiedName);
                  classes.add(clazz);
                  if (!clazz.isAnnotation())
                  {
                     Class<?>[] clazzInterfaces = clazz.getInterfaces();
                     if (Arrays.asList(clazzInterfaces).contains(BaseDao.class))
                     {
                        baseDaoClasses.add(clazz);
                     }
                     if (clazz.isAnnotationPresent(Table.class))
                     {
                        entityClasses.add(clazz);
                     }
                  }
               }
               else if (f.isDirectory())
               {
                  loadClasses(f);
               }
            }
         }
      }
   }
}

7. Main类是该实例的主类,使用方法模仿springboot


import java.sql.SQLException;

public class Main
{
   @AutoWired
   private PersonDao personDao;

   public void personDaoTest() throws SQLException
   {
      personDao.create(new Person());
      personDao.insert(new Person(2, "小明", 18));
      System.out.println("插入成功!");
      Person person = personDao.selectById(2L);
      System.out.println("查询到的信息:" + person);
      personDao.update(new Person(2, null, 28));
      System.out.println("更新成功!");
      personDao.selectById(2L);
      System.out.println("更新后的值:" + person);
      personDao.deleteById(2L);
      System.out.println("删除成功!");
   }

   public static void main(String[] args) throws SQLException
   {
      Application application = Application.run();
      Main main = (Main) application.getClass(Main.class);
      main.personDaoTest();
   }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值