Spring 关于bean的获取以及自定义注解的起始注入和获取

    最近有收获了一点东西,特来记录。假设一个场景,一个学生的学习计划根据其不同的人,和学习内容有不同的结果,和处理方式。按照我们正常的写法,应该是就是构造一个’内容‘接口。例如

public interface PersonAnnotationService {

	public String testPrint();
}


   接下来我们应该制造很多实现类,区分人和学习内容来根据不同的情况获取不同的实现类。这就麻烦了,一,我们怎么区分这两个条件呢,二,区分了我们怎么能简单的,不模糊的获取对应的实现类呢

     方法一:如果用一对一架构关系的话,也是有办法的。比如我们,创建一个子接口去继承内容接口

public interface PersonZxyCoding extends PersonAnnotationService{

}
然后去创建一个子接口的实现类去实现内容接口

@Service
public class PersonZxyCodingImpl implements PersonZxyCoding{

	@Override
	public String testPrint() {
		System.err.println("这里是son:PersonZxyCodingImpl");
		return null;
	}

}
再在Controller出调用,这样就可以实现目标了。即--》谁:Zxy   干什么:Coding。每个人+每个事 对应一个子接口就完成了

	@Autowired
	private PersonZxyCoding personZxyCoding;

这是实现的第一种办法,很简单。现在回归我们的主题,我们需要注意的是,如果,我有一个班五十二个人,每个人都有dancing和coding两种或者更多的同样内容细节要编写,那就很可怕了。那就是至少52*2=104个类。在这种情况下,也许我们可以考虑换个方法。

     方法二:所有的内容实现类继承一个接口。如

xx  extends PersonAnnotationService 

      然后申明一个自定义接口,对这个自定义接口传入==》人+内容的有关条件。然后在编写实现类的时候对于实现类上,添加自定义接口,并标明有关字段,spring 启动的时候获取有关实现类的bean。放在Map<String,Object>里面,在需要方法时,通过getKey(人+内容)获取对应的实现类。

      详细说下这个过程就是,

      1.创建一个有关接口

@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Service
public @interface personInfo {
    String personInfo() default "0";
    String value() default "";
}
     2.编写实现类的时候对实现类加入对应注解

@Service
@personInfo(personInfo=config.personInfoCoding)
public class PersonCodingServiceimpl implements PersonAnnotationService
     3.编写getContent类,实现ApplicationContextAware,实现该接口的的原因是,此接口可以在载入的时候,把ApplicationContext接收到,以此来获得所有的bean(通过getbean就能获取到对应的类),同时此类也可以当做一个spring工具类,负责有关getbean,反射获取对应类,根据注解类,获取有此注解类注解的有关类的功能。

ps:此处业务分析,详细代码在最后面给出

private static ApplicationContext applicationContext;
	//全局保存相关的personBean实现对象
	public static Map<String, Object> getPersonbeanmap = new HashMap<String, Object>();
        
        // 获取Spring的application到该类
        @Override
	public void setApplicationContext(ApplicationContext arg0) throws BeansException {
		getContent.applicationContext = arg0;
	}

	// 通过反射操作获取对应的类
	public static Object getTarget(Object proxy) throws Exception {
		if (!AopUtils.isAopProxy(proxy)) {
			return proxy;// 不是代理对象
		}
		// 根据jdk进行反射操作
		if (AopUtils.isJdkDynamicProxy(proxy)) {
			return getJdkDynamicProxyTargetObject(proxy);
		} else { // 根据cglib进行反射操作
			return getCglibProxyTargetObject(proxy);
		}
	}


	@SuppressWarnings("unchecked")
	public static <T> T getBean(String beanName) {
		cheakApplicationContext();
		return (T) applicationContext.getBean(beanName);
	}

	public static <T> T getBean(Class<T> clazz) {
		cheakApplicationContext();
		return (T) applicationContext.getBean(clazz);
	}

	// 根据传入的自定义注解的类,从Application获取有此注解的所有类
	public static Map<String, Object> getMapbeanwithAnnotion(Class<? extends Annotation> cls) {
		Map<String, Object> map = new HashMap<String, Object>();
		map = applicationContext.getBeansWithAnnotation(cls);
		return map;
	} 


      4.现在我们可以想象的是,Spring启动的时候,有关注解的实现类,将会以bean的形式存入容器中,而我们也编写了获取bean和获取相关类的方法。那么接下来,我们需要做的,是在启动时候,把实现类,放在map中,通过,Map<'人+内容',‘实现类’>的形式保存。在需要的时候直接getKey获取有关的实现类。

       在这里我们需要实现ApplicationListener<ContextRefreshedEvent>接口,该接口的作用是在Spring启动的最后阶段,Spring自动执行该接口的方法onApplicationEvent。

       所有我们可以把需要spring执行的有关方法放在这里面,在本环境,我们需要做的事,把map处理成上述的格式。

@Service
public class initContent implements ApplicationListener<ContextRefreshedEvent> {

	@Override
	public void onApplicationEvent(ContextRefreshedEvent event) {
		// 通过注解获取相关的类
		Map<String, Object> map = getContent.getMapbeanwithAnnotion(personInfo.class);
		for (Map.Entry<String, Object> entrymap : map.entrySet()) {
			try {
				// 通过反射获取相关的实现类的Object
				Object object = getContent.getTarget(entrymap.getValue());
				if (object != null) {
					PersonAnnotationService annotationService = (PersonAnnotationService) object;
					// 不为空的情况下,获取实现类的注解对象
					// 并把注解对象的注解字段当做map的Key,实现类Object当做值
					personInfo info = annotationService.getClass().getAnnotation(personInfo.class);
					getContent.getPersonbeanmap.put(info.personInfo(), object);
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
}
    5.现在所有的实现类已经按照Map<'人+内容',‘实现类’>的格式存入map里面。我们只需在调用的时候按照对应需要的Key值获取有关的实现类了。

      

	@Autowired
	private PersonService personService;
	
	@Autowired
	private PersonZxyCoding personZxyCoding;

	@RequestMapping("/text")
	public String index() {
		//第一种方式获取有关的实现类
		PersonAnnotationService annotationService=personZxyCoding;
		annotationService.testPrint();
		
		//第二种方式获取有关的实现类
		PersonAnnotationService personService=(PersonAnnotationService) getContent.getPersonbeanmap.get(config.personInfoCoding);
		personService.testPrint();
		return "Hellow my friend.  my name is Spring BOOT";
		
	}

结果:

     




附:getContent详细代码

@Service
public class getContent implements ApplicationContextAware {

	private static ApplicationContext applicationContext;

	//全局保存相关的personBean实现对象
	public static Map<String, Object> getPersonbeanmap = new HashMap<String, Object>();

	// 获取Spring的application到该类
	@Override
	public void setApplicationContext(ApplicationContext arg0) throws BeansException {
		getContent.applicationContext = arg0;
	}

	public static ApplicationContext getApplicationContext() {
		return applicationContext;
	}

	@SuppressWarnings("unchecked")
	public static <T> T getBean(String beanName) {
		cheakApplicationContext();
		return (T) applicationContext.getBean(beanName);
	}

	public static <T> T getBean(Class<T> clazz) {
		cheakApplicationContext();
		return (T) applicationContext.getBean(clazz);
	}

	// 根据传入的自定义注解的类,从Application获取有此注解的所有类
	public static Map<String, Object> getMapbeanwithAnnotion(Class<? extends Annotation> cls) {
		Map<String, Object> map = new HashMap<String, Object>();
		map = applicationContext.getBeansWithAnnotation(cls);
		return map;
	}

	// 空值检测
	private static void cheakApplicationContext() {
		if (applicationContext == null) {
			throw new IllegalStateException("applicaitonContext未注入,请在applicationContext.xml中定义SpringContextHolder");
		}
	}

	// 通过反射操作获取对应的类
	public static Object getTarget(Object proxy) throws Exception {
		if (!AopUtils.isAopProxy(proxy)) {
			return proxy;// 不是代理对象
		}
		// 根据jdk进行反射操作
		if (AopUtils.isJdkDynamicProxy(proxy)) {
			return getJdkDynamicProxyTargetObject(proxy);
		} else { // 根据cglib进行反射操作
			return getCglibProxyTargetObject(proxy);
		}
	}

	private static Object getCglibProxyTargetObject(Object proxy) throws Exception {
		Field h = proxy.getClass().getDeclaredField("CGLIB$CALLBACK_0");
		h.setAccessible(true);
		Object dynamicAdvisedInterceptor = h.get(proxy);
		Field advised = dynamicAdvisedInterceptor.getClass().getDeclaredField("advised");
		advised.setAccessible(true);
		Object target = ((AdvisedSupport) advised.get(dynamicAdvisedInterceptor)).getTargetSource().getTarget();
		return target;
	}

	private static Object getJdkDynamicProxyTargetObject(Object proxy) throws Exception {
		Field h = proxy.getClass().getSuperclass().getDeclaredField("h");
		h.setAccessible(true);
		AopProxy aopProxy = (AopProxy) h.get(proxy);
		Field advised = aopProxy.getClass().getDeclaredField("advised");
		advised.setAccessible(true);
		Object target = ((AdvisedSupport) advised.get(aopProxy)).getTargetSource().getTarget();
		return target;
	}

}




  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
获取添加了自定义注解的所有方法,你可以使用 Spring 的反射机制。下面是一个示例代码,演示了如何获取添加了指定注解的所有方法: ```java import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.core.annotation.AnnotationUtils; import org.springframework.stereotype.Component; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; @Component public class AnnotationMethodProcessor implements BeanPostProcessor { private List<Method> annotatedMethods = new ArrayList<>(); @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { Class<?> clazz = bean.getClass(); Method[] methods = clazz.getDeclaredMethods(); for (Method method : methods) { if (AnnotationUtils.findAnnotation(method, YourCustomAnnotation.class) != null) { annotatedMethods.add(method); } } return bean; } public List<Method> getAnnotatedMethods() { return annotatedMethods; } } ``` 在上面的示例代码中,首先,你需要在自定义的注解处理器类(例如上述示例中的 `AnnotationMethodProcessor`)上添加 `@Component` 注解,以便让 Spring 容器自动扫描并进行初始化。然后,你可以在 `postProcessBeforeInitialization` 方法中使用 `AnnotationUtils.findAnnotation` 方法来判断方法是否添加了指定的自定义注解,并将这些方法添加到 `annotatedMethods` 列表中。 接下来,你可以在需要获取添加了自定义注解的所有方法的地方使用 `AnnotationMethodProcessor` 类。例如: ```java List<Method> annotatedMethods = annotationMethodProcessor.getAnnotatedMethods(); ``` 这样,`annotatedMethods` 列表中就包含了添加了自定义注解的所有方法的 `Method` 对象。你可以根据需要进一步处理这些方法。请注意,你需要保证 `AnnotationMethodProcessor` 类已经被 Spring 容器正确初始化,才能获取到正确的结果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值