SSM 소스 코드 분석의 Spring 08 - 핸드폰 SpringV 2.0

디 렉 터 리 탐색
  • 서문
  • 핸드폰 SpringV 2.0
  • 모든 것 은 ApplicationContext 컨 텍스트 에서 시작 합 니 다
  • BeanDefinitionReader 는 설정 파일 을 찾 아 읽 고 해석 합 니 다
  • BeanDefinition 은 설정 파일 의 정 보 를 저장 하 는 데 사 용 됩 니 다
  • BeanWrapper
  • BeanPostProcessor 용 사건 감청
  • refresh 방법 으로 포 지 셔 닝, 로드, 등록 기능 실현
  • 후기
  • 머리말
    이 소절, 우 리 는 spring 소스 코드 에 따라 IOC 와 AOP 소스 코드 를 한층 더 봉인 합 니 다 ~
    핸드폰 SpringV 2.0
    모든 것 은 Application Context 컨 텍스트 에서 시작 합 니 다.
    spring 의 Application Context 의 가장 핵심 적 인 방법 은 refresh 입 니 다. 이것 은 우리 가 전에 말 했 기 때문에 제 가 먼저 refresh 방법 을 미리 남 겨 두 었 습 니 다.
    public class GPApplicationContext{
    
    	 public void refresh(){}
    	 
    }
    

    그리고 BeanFactory 를 실현 시 키 도록 하 겠 습 니 다.
    public interface GPBeanFactory {
    
        /**
         *   beanName IOC          Bean
         * @param beanName
         * @return
         */
        Object getBean(String beanName);
    
    }
    

    획득:
    public class GPApplicationContext implements GPBeanFactory {
    
        private String [] configLocations;
    
        private GPBeanDefinitionReader reader;
    
        //            
        private Map<String,Object> beanCacheMap = new HashMap<String, Object>();
    
        //              
        private Map<String,GPBeanWrapper> beanWrapperMap = new ConcurrentHashMap<String, GPBeanWrapper>();
    
    	
    	 public GPApplicationContext(String ... configLocations){
            this.configLocations = configLocations;
            refresh();
        }
    	
            //    ,     ,    BeanDefinition    
        //  ,               
        //Spring   ,            ,    BeanWrapper       
        //     :
        //1、     OOP  
        //2、         ,  (    AOP   )
        @Override
        public Object getBean(String beanName) {
    
            GPBeanDefinition beanDefinition = this.beanDefinitionMap.get(beanName);
    
            String className = beanDefinition.getBeanClassName();
    
            try{
    
                //      
                GPBeanPostProcessor beanPostProcessor = new GPBeanPostProcessor();
    
                Object instance = instantionBean(beanDefinition);
                if(null == instance){ return  null;}
    
                //            
                beanPostProcessor.postProcessBeforeInitialization(instance,beanName);
    
                GPBeanWrapper beanWrapper = new GPBeanWrapper(instance);
                beanWrapper.setAopConfig(instantionAopConfig(beanDefinition));
                beanWrapper.setPostProcessor(beanPostProcessor);
                this.beanWrapperMap.put(beanName,beanWrapper);
    
                //            
                beanPostProcessor.postProcessAfterInitialization(instance,beanName);
    
    //            populateBean(beanName,instance);
    
                //       ,                 
                return this.beanWrapperMap.get(beanName).getWrappedInstance();
            }catch (Exception e){
                e.printStackTrace();
            }
    
            return null;
        }
    
        private GPAopConfig instantionAopConfig(GPBeanDefinition beanDefinition) throws  Exception{
            GPAopConfig config = new GPAopConfig();
            String expression = reader.getConfig().getProperty("pointCut");
            String[] before = reader.getConfig().getProperty("aspectBefore").split("\\s");
            String[] after = reader.getConfig().getProperty("aspectAfter").split("\\s");
    
            String className = beanDefinition.getBeanClassName();
            Class<?> clazz = Class.forName(className);
    
            Pattern pattern = Pattern.compile(expression);
    
            Class aspectClass = Class.forName(before[0]);
            //               
            for (Method m : clazz.getMethods()){
    
                //public .* com\.gupaoedu\.vip\.spring\.demo\.service\..*Service\..*\(.*\)
                //public java.lang.String com.gupaoedu.vip.spring.demo.service.impl.ModifyService.add(java.lang.String,java.lang.String)
                Matcher matcher = pattern.matcher(m.toString());
                if(matcher.matches()){
                    //         ,   AOP   
                    config.put(m,aspectClass.newInstance(),new Method[]{aspectClass.getMethod(before[1]),aspectClass.getMethod(after[1])});
                }
            }
    
    
    
            return  config;
        }
    
    
    
    
        //   BeanDefinition,       Bean
        private Object instantionBean(GPBeanDefinition beanDefinition){
            Object instance = null;
            String className = beanDefinition.getBeanClassName();
            try{
    
    
                //    Class            
                if(this.beanCacheMap.containsKey(className)){
                    instance = this.beanCacheMap.get(className);
                }else{
                    Class<?> clazz = Class.forName(className);
                    instance = clazz.newInstance();
                    this.beanCacheMap.put(className,instance);
                }
    
                return instance;
            }catch (Exception e){
                e.printStackTrace();
            }
    
            return null;
        }
    }
    

    BeanDefinitionReader 는 설정 파일 을 찾 고 읽 고 해석 합 니 다.
    public class GPBeanDefinitionReader {
    
        private  Properties config = new Properties();
    
        private List<String> registyBeanClasses = new ArrayList<String>();
    
    
        //      ,            key
        private final String SCAN_PACKAGE = "scanPackage";
    
        public GPBeanDefinitionReader(String... locations){
            // Spring    Reader         
            InputStream is = this.getClass().getClassLoader().getResourceAsStream(locations[0].replace("classpath:",""));
    
            try {
                config.load(is);
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                try {
                    if(null != is){is.close();}
                }catch (Exception e){
                    e.printStackTrace();
                }
    
            }
    
            doScanner(config.getProperty(SCAN_PACKAGE));
    
        }
    
    
        public List<String> loadBeanDefinitions(){
            return this.registyBeanClasses;
        }
    
    
        //     className,     BeanDefinition,     
        //               
        public GPBeanDefinition registerBean(String className){
            if(this.registyBeanClasses.contains(className)){
                GPBeanDefinition beanDefinition = new GPBeanDefinition();
                beanDefinition.setBeanClassName(className);
                beanDefinition.setFactoryBeanName(lowerFirstCase(className.substring(className.lastIndexOf(".") + 1)));
                return beanDefinition;
            }
    
            return null;
        }
    
    
        //           class,       List 
        private void doScanner(String packageName) {
    
            URL url = this.getClass().getClassLoader().getResource("/" + packageName.replaceAll("\\.","/"));
    
            File classDir = new File(url.getFile());
    
            for (File file : classDir.listFiles()){
                if(file.isDirectory()){
                    doScanner(packageName + "." +file.getName());
                }else {
                    registyBeanClasses.add(packageName + "." + file.getName().replace(".class",""));
                }
            }
    
    
        }
    
    
        public Properties getConfig(){
            return this.config;
        }
    
    
    
        private String lowerFirstCase(String str){
            char [] chars = str.toCharArray();
            chars[0] += 32;
            return String.valueOf(chars);
        }
    
    }
    

    BeanDefinition 은 설정 파일 의 정 보 를 저장 하 는 데 사 용 됩 니 다.
    BeanDefinition 은 메모리 에 저 장 된 설정 에 해당 합 니 다.
    public class GPBeanDefinition {
    
        private String beanClassName;
        private boolean lazyInit = false;
        private String factoryBeanName;
    
        public String getBeanClassName() {
            return beanClassName;
        }
    
        public void setBeanClassName(String beanClassName) {
            this.beanClassName = beanClassName;
        }
    
        public boolean isLazyInit() {
            return lazyInit;
        }
    
        public void setLazyInit(boolean lazyInit) {
            this.lazyInit = lazyInit;
        }
    
        public String getFactoryBeanName() {
            return factoryBeanName;
        }
    
        public void setFactoryBeanName(String factoryBeanName) {
            this.factoryBeanName = factoryBeanName;
        }
    
    }
    

    BeanWrapper
    public class GPBeanWrapper extends GPFactoryBean {
    
        private GPAopProxy aopProxy = new GPAopProxy();
    
        public GPBeanPostProcessor getPostProcessor() {
            return postProcessor;
        }
    
        public void setPostProcessor(GPBeanPostProcessor postProcessor) {
            this.postProcessor = postProcessor;
        }
    
        //             
        //1、      ,      
        private GPBeanPostProcessor postProcessor;
    
        private Object wrapperInstance;
        //       new  ,      ,   
        private Object originalInstance;
    
        public GPBeanWrapper(Object instance){
            //     ,              
            this.wrapperInstance = aopProxy.getProxy(instance);
            this.originalInstance = instance;
        }
    
        public Object getWrappedInstance(){
            return this.wrapperInstance;
        }
    
    
        //        Class
        //        $Proxy0
        public Class<?> getWrappedClass(){
            return this.wrapperInstance.getClass();
        }
    
    
        public void setAopConfig(GPAopConfig config){
            aopProxy.setConfig(config);
        }
    
    
        public Object getOriginalInstance() {
            return originalInstance;
        }
    }
    

    BeanPost Processor 는 사건 감청 으로 사용 합 니 다.
    public class GPBeanPostProcessor {
    
        public Object postProcessBeforeInitialization(Object bean, String beanName) {
            return bean;
        }
        public Object postProcessAfterInitialization(Object bean, String beanName){
            return bean;
        }
    
    }
    

    refresh 방법 은 포 지 셔 닝, 로드, 등록 기능 을 실현 합 니 다.
    applicationContext 컨 텍스트 라 는 핵심 클래스 로 돌아 가 refresh 방법 을 실현 합 니 다.
        public void refresh(){
            //  
            this.reader = new GPBeanDefinitionReader(configLocations);
    
            //  
            List<String> beanDefinitions = reader.loadBeanDefinitions();
    
            //  
            doRegisty(beanDefinitions);
    
    
            //    (lazy-init = false),        
            //       getBean  
            doAutowrited();
    
    //        MyAction myAction = (MyAction)this.getBean("myAction");
    //        myAction.query(null,null,"   Tom  ");
        }
    

    그리고 등록 실현:
    //    BeanDefinitions   beanDefinitionMap 
    
        private void doRegisty(List<String> beanDefinitions) {
    
    
            //beanName     :
            //1、          
            //2、     
            //3、    
            try {
                for (String className : beanDefinitions) {
    
                    Class<?> beanClass = Class.forName(className);
    
                    //       ,       
                    //         
                    if(beanClass.isInterface()){ continue; }
    
                    GPBeanDefinition beanDefinition = reader.registerBean(className);
                    if(beanDefinition != null){
                        this.beanDefinitionMap.put(beanDefinition.getFactoryBeanName(),beanDefinition);
                    }
    
    
                    Class<?>[] interfaces = beanClass.getInterfaces();
                    for (Class<?> i: interfaces) {
                        //        ,    
                        //   ?  Spring     ,     
                        //    ,       
                        this.beanDefinitionMap.put(i.getName(),beanDefinition);
                    }
    
    
                    //     ,       
    
                }
            }catch (Exception e){
                e.printStackTrace();
            }
    
        }
    
    

    자동 주입 실현:
        //            
        private void doAutowrited() {
    
    
            for(Map.Entry<String,GPBeanDefinition> beanDefinitionEntry : this.beanDefinitionMap.entrySet()){
                String beanName = beanDefinitionEntry.getKey();
    
                if(!beanDefinitionEntry.getValue().isLazyInit()){
                    Object obj = getBean(beanName);
    //                System.out.println(obj.getClass());
                }
    
            }
    
    
            for(Map.Entry<String,GPBeanWrapper> beanWrapperEntry : this.beanWrapperMap.entrySet()){
    
                populateBean(beanWrapperEntry.getKey(),beanWrapperEntry.getValue().getOriginalInstance());
    
            }
    
    //        System.out.println("===================");
    
    
        }
    
    
    
        public void populateBean(String beanName,Object instance){
    
            Class clazz = instance.getClass();
    
            //           
            if(!(clazz.isAnnotationPresent(GPController.class) ||
                    clazz.isAnnotationPresent(GPService.class))){
                return;
            }
    
    
            Field [] fields = clazz.getDeclaredFields();
    
            for (Field field : fields) {
                if (!field.isAnnotationPresent(GPAutowired.class)){ continue; }
    
                GPAutowired autowired = field.getAnnotation(GPAutowired.class);
    
                String autowiredBeanName = autowired.value().trim();
    
                if("".equals(autowiredBeanName)){
                    autowiredBeanName = field.getType().getName();
                }
    
                field.setAccessible(true);
    
                try {
    
                    //System.out.println("=======================" +instance +"," + autowiredBeanName + "," + this.beanWrapperMap.get(autowiredBeanName));
                    field.set(instance,this.beanWrapperMap.get(autowiredBeanName).getWrappedInstance());
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
    
            }
    
    
    
        }
    

    후기
    springV 2.0 github 주소

    좋은 웹페이지 즐겨찾기