实现自定义注解主要分三个步骤:
1.定义自己的注解类。
注解类默认继承Annotation接口。
且注解内的属性默认public(要给别人用的)
属性可以定义默认值也就是不给你的属性传值也会拥有默认。
注解里只允许基本类型,加上枚举,注解,String。
/** * author: Badfsiher(yhy) * date 2020/6/17 20:51 */
@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.TYPE,ElementType.METHOD})
@Documented
public @interface MyService {
String value();
public String name() default "my service !";
}
/** * author: Badfsiher(yhy) * date 2020/6/17 21:12 */ @Retention(RetentionPolicy.RUNTIME) @Target(value = {ElementType.FIELD}) @Documented public @interface MyAutowired { String value() default "my ioc Autowired"; String name(); Class clazz(); }
/** * author: Badfsiher(yhy) * date 2020/6/17 21:12 */ @Retention(RetentionPolicy.RUNTIME) @Target(value = {ElementType.FIELD}) @Documented public @interface MyTransactional { }
然后解释一下我是用的注解上的几个元注解含义。
@Retention这个标志这需要在什么时候执行,也就三种编译时,解释时,运行时。
@Target这个主要定义你的注解使用的范围在方法属性,类名上等可以多个范围。
@Documented这个是标识可以输出到javadoc文档中
2.使用自定义注解标记实用位置
根据自己定义的注解适用范围为自己的类或者属性做好自己的注解
/** * author badfisher */ @MyService @MyTransactional public class TransferServiceImpl implements TransferService { @MyAutowired(name="AccountDao",clazz = JdbcAccountDaoImpl.class) private AccountDao accountDao; @MyAutowired(name="TransactionManager",clazz = TransactionManager.class) private TransactionManager transactionManager; public TransferServiceImpl() throws SQLException { }
3.获取自己标记的方法和类完成相应的逻辑。
public static <T> T getClass(String clazz) throws Exception{ //扫描需要的类 Class result = null; try { result = Class.forName(clazz); } catch (ClassNotFoundException e) { System.out.println("类加载失败!"); e.printStackTrace(); } //获取所有属性 Field[] fields = result.getDeclaredFields(); T res = (T) result.getDeclaredConstructor().newInstance(); //接口名称 String intfceName = ""; for (Field field : fields){ // 获取属性上 MyAutowired myAutowired = field.getAnnotation(MyAutowired.class); if (myAutowired != null){ intfceName =myAutowired.name(); Object object = getClass(myAutowired.clazz()); map.put(intfceName,object); if (!field.isAccessible()) field.setAccessible(true); try { field.set(res,object); } catch (IllegalAccessException e) { e.printStackTrace(); System.out.println("MyAutowired the " + field.getName() + "failed!!"); } } } map.put(intfceName,res); return res; } // 对外提供获取实例对象的接口(根据id获取) public static Object getBean(String id) { return map.get(id); }
中间考虑到注入的类中还有存在依赖那么我们会继续对他进行检查知道这一条业务所有类反射出来。
事物方面,获取注解后使用动态代理可以很简单控制方法。
/** * Jdk动态代理 */ public Object getJdkProxy(Object obj) { // 获取代理对象 return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object result = null; try{ // 开启事务(关闭事务的自动提交) transactionManager.beginTransaction(); result = method.invoke(obj,args); // 提交事务 transactionManager.commit(); }catch (Exception e) { e.printStackTrace(); // 回滚事务 transactionManager.rollback(); // 抛出异常便于上层servlet捕获 throw e; } return result; } }); }
以上就是相关整体功能实现和主要代码了。