最近有收获了一点东西,特来记录。假设一个场景,一个学生的学习计划根据其不同的人,和学习内容有不同的结果,和处理方式。按照我们正常的写法,应该是就是构造一个’内容‘接口。例如
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详细说下这个过程就是,
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 getPersonbeanmap = new HashMap();
// 获取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 getBean(String beanName) {
cheakApplicationContext();
return (T) applicationContext.getBean(beanName);
}
public static T getBean(Class clazz) {
cheakApplicationContext();
return (T) applicationContext.getBean(clazz);
}
// 根据传入的自定义注解的类,从Application获取有此注解的所有类
public static Map getMapbeanwithAnnotion(Class extends Annotation> cls) {
Map map = new HashMap();
map = applicationContext.getBeansWithAnnotation(cls);
return map;
}
在这里我们需要实现ApplicationListener
所有我们可以把需要spring执行的有关方法放在这里面,在本环境,我们需要做的事,把map处理成上述的格式。
@Service
public class initContent implements ApplicationListener {
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
// 通过注解获取相关的类
Map map = getContent.getMapbeanwithAnnotion(personInfo.class);
for (Map.Entry 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 getPersonbeanmap = new HashMap();
// 获取Spring的application到该类
@Override
public void setApplicationContext(ApplicationContext arg0) throws BeansException {
getContent.applicationContext = arg0;
}
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
@SuppressWarnings("unchecked")
public static T getBean(String beanName) {
cheakApplicationContext();
return (T) applicationContext.getBean(beanName);
}
public static T getBean(Class clazz) {
cheakApplicationContext();
return (T) applicationContext.getBean(clazz);
}
// 根据传入的自定义注解的类,从Application获取有此注解的所有类
public static Map getMapbeanwithAnnotion(Class extends Annotation> cls) {
Map map = new HashMap();
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;
}
}