本节主要通过一个自定义注解了解注解是什么,然后简要介绍下spring注解分类和作用,最后简要概括一下web spring容器初始化过程;

1、自定义Annotation_my注解

@Target({ElementType.METHOD,ElementType.TYPE})
@Inherited
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface Annotation_my {

    String name() default "张三";//defalt 表示默认值
    
    String say() default "hello world";
    
    int age() default 21;
}

上面是按照定义规范自定义一个注解接口,@Annotation_my,你也可以把注解理解为一个接口,其实他就是一个注释作用;然后定义person接口

public interface Person {

    public void name();

    public void say();
    

    public void age();
}

实现接口(student)

@Annotation_my
@SuppressWarnings("unused")
public class Student implements Person {

       private String name;

        @Override
        @Annotation_my(name="流氓公子") //赋值给name  默认的为张三
    //在定义注解时没有给定默认值时,在此处必须name赋初值
        public void name() {
            
        }


        @Override
        @Annotation_my(say=" hello world  !")
        public void say() {
            
        }

        @Override
        @Annotation_my(age=20)
        public void age() {
            
        }
}

这里使用了上面自定义注解,在类外部使用,相当于@Component,然后方法上面定义的注解,相当于方法的注解;最后我们来使用test类测试一下效果,如下:

public class Test {

    Annotation[] annotation = null;

    public static void main(String[] args) throws ClassNotFoundException {
        new Test().getAnnotation();
    }
    public void getAnnotation() throws ClassNotFoundException{
        Class<?> stu = Class.forName("com.qzx.web.anotation.Student");//静态加载类
        boolean isEmpty = stu.isAnnotationPresent(com.qzx.web.anotation.Annotation_my.class);//判断stu是不是使用了我们刚才定义的注解接口
        if(isEmpty){
            annotation = stu.getAnnotations();//获取注解接口中的
            for(Annotation a:annotation){
                Annotation_my my = (Annotation_my)a;//强制转换成Annotation_my类型
                System.out.println(stu+":\n"+my.name()+" say: "+my.say()+" my age: "+my.age());
            }
        }
        Method[] method = stu.getMethods();//
        System.out.println("Method");
        for(Method m:method){
            boolean ismEmpty = m.isAnnotationPresent(com.qzx.web.anotation.Annotation_my.class);
            if(ismEmpty){
                Annotation[] aa = m.getAnnotations();
                for(Annotation a:aa){
                    Annotation_my an = (Annotation_my)a;
                    System.out.println(m+":\n"+an.name()+" say: "+an.say()+" my age: "+an.age());
                }
            }
        }
        //get Fields by force
        System.out.println("get Fileds by force !");
        Field[] field = stu.getDeclaredFields();
        for(Field f:field){
            f.setAccessible(true);
            System.out.println(f.getName());
        }
        System.out.println("get methods in interfaces !");
        Class<?> interfaces[] = stu.getInterfaces();
        for(Class<?> c:interfaces){
            Method[] imethod = c.getMethods();
            for(Method m:imethod){
                System.out.println(m.getName());
            }
        }
        
    }
    
}

通过测试可以知道,注解其实就是注释的作用,annotation = stu.getAnnotations();通过注释(绑定到类或方法上),可以给当前对象定义一系列初始操作,比如定义类名称,其他属性等;这样定义好后,spring容器扫描类时候,就能通过注解找到不同定义类型的类,然后进行初始化对象等操作。

2、下面介绍一下spring经常使用的注解

通用类注解 @component,业务层注解@Service,数据访问层@Reposity ,controller控制器层@Controller,事务@Transaction,相当于xml配置时候的class;@Autowired@Resource对类内部成员属性进行注解,相当于xml配置的property。使用时候根据情况,可以设置name值,比如@Component("boss"),因为初始化时默认类是singleton的,这个boss相当于xml配置的id名称,也就是对象id,到时候对象工厂可以通过BeanFactory bf = (BeanFactory) reg;
Object o = bf.getBean("boss")来找到对象。

3、springmvc初始化过程

tomcat容器为例,当启动web服务时候,初始化spring容器,web.xml中两个地方配置;一个是监听,一个是dispatcher,如下:

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:beans.xml</param-value>
  </context-param>
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>

和 <servlet>
    <servlet-name>springmvc</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:spring-mvc.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>

web加载配置文件,首先初始化spring监听服务,读取beans.xml配置文件,该文件一般配置有数据源、SqlSessionFactory、事务和bean等,按照顺序加载,当读取到 <context:component-scan base-package ="com" />配置时候,打开spring扫描操作,容器会读取com目录及子目录,扫描含有@注解标志的class文件,扫描是按照类目递归进行:比如,扫描com.controller目录的一个userAction类时,上面含有@Controller注解,beanfactory装配该类实例(初始化就是生成beanDefinition的实例,BeanDefinition实例是用来描述Bean结构,一般还没有实例化bean)将beanDefinition实例放入Bean工厂,接着扫描类文件中含有@注解的属性,比如@AutoWire或@Resource的属性,一般是service,装配该类,放入工厂;如此反复进行,装配所有类文件。具体过程可以参考https://my.oschina.net/HeliosFly/blog/203149这篇文章。

至于DispatcherServlet这个配置,就是映射控制器中的方法、url路径信息等,比如@RequestMapping("/index.do"),装配userAction--methodName--url(index.do)。这样映射后,当访问http方法时候,就能找到路径,然后就可以调用方法了。这些只是我大致理解,里面有些知识点也不是很清晰,可以自己去查看相关资料,推荐https://my.oschina.net/HeliosFly/blog/203149

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐