Spring注解开发详细教程 (配合雷神的视频)
一、AnnotationConfigApplicationContext
1.配置类
1.1使用传统xml方式
applicationContext.xml:
<bean id="person" class="com.rg.domain.Person" > <property name="name" value="张三"/> <property name="age" value="19"/> </bean>
person类:
package com.rg.domain; public class Person { private String name; private Integer age; public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public Person(String name, Integer age) { this.name = name; this.age = age; } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
测试类:
@Test public void test01(){ //加载配置文件 ApplicationContext applicationContext = new ClassPathXmlApplicationContext("ApplicationContext.xml"); Person person = (Person) applicationContext.getBean("person");//通过id获取实体 System.out.println(person); }
1.2使用配置类方式:
MainConfig 配置类
//配置类==配置文件 @Configuration //告诉Spring这是一个配置类 public class MainConfig { //给容器注册一个Bean;类型为返回值的类型,id默认是用方法名作为id @Bean("person") //修改方法名称 public Person person(){ return new Person("lisi",20); } }
测试类
@Test public void test02(){ ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class); Person person = applicationContext.getBean(Person.class);//通过类名来获取 System.out.println(person); }
2.包扫描
2.1传统xml方式:
<!--包扫描,只要标注了@Controller,@service,@Repository,@Component 类对象就会被自动加载到IOC容器中--> <context:component-scan base-package="com.rg"/>
2.2注解方式:
MainConfig配置类
//配置类==配置文件 @Configuration //告诉Spring这是一个配置类 @ComponentScan("com.rg") public class MainConfig { //给容器注册一个Bean;类型为返回值的类型,id默认是用方法名作为id @Bean("person") //修改方法名称 public Person person(){ return new Person("lisi",20); } }
项目结构:
其中controller,dao,service中的类均使用相对应的注解.
测试类:
@Test public void test03(){ ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class); String[] names = applicationContext.getBeanDefinitionNames();//获取容器中所有的对象名称 for (String name : names) { System.out.println(name); } }
运行结果:
二、组件添加
1.@ComponentScan
1.1传统xml
<!--包扫描,只要标注了@Controller,@service,@Repository,@Component 类对象就会被自动加载到IOC容器中--> <context:component-scan base-package="com.rg" use-default-filters="false"> <!--use-default-filters : 是否使用默认的过滤器,默认值true 扫描包中的全部文件--> <!-- 注意:若使用include-filter去定制扫描内容,要在use-default-filters="false"的情况下,不然会“失效”,被默认的过滤机制所覆盖 --> type可为regex (正则),annotation(注解),assignable(接口或类) <context:exclude-filter type="assignable" expression="com.rg.controller.BookController"/> <context:include-filter type="assignable" expression="com.rg.service.BookService"/> </context:component-scan>
1.2使用配置类
1.2.1ComponentScan注解的基本使用
//配置类==配置文件 @Configuration //告诉Spring这是一个配置类 //JDK8之后可以写多个ComponentScan;如果不是该版本则可 使用ComponentScans属性 //注意 @ComponentScan(value="com.rg",includeFilters = { @ComponentScan.Filter(type=FilterType.ANNOTATION,classes={Controller.class})}, useDefaultFilters = false) @ComponentScans( value = { @ComponentScan(value="com.rg",includeFilters = { @ComponentScan.Filter(type=FilterType.ANNOTATION,classes={Controller.class}),//第一个过滤器,根据注解类型 @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,classes = {BookService.class}),//根据给定的类型 }, useDefaultFilters = false), @ComponentScan(), //... } ) //@ComponentScan value:指定要扫描的包 //excludeFilters = Filter[] :指定扫描的时候按照什么规则排除那些组件 //includeFilters = Filter[] :指定扫描的时候只需要包含哪些组件 //FilterType.ANNOTATION:按照注解 //FilterType.ASSIGNABLE_TYPE:按照给定的类型; //FilterType.ASPECTJ:使用ASPECTJ表达式 //FilterType.REGEX:使用正则指定 //FilterType.CUSTOM:使用自定义规则 public class MainConfig { //给容器注册一个Bean;类型为返回值的类型,id默认是用方法名作为id @Bean("person") //修改方法名称 public Person person(){ return new Person("lisi",20); } }
测试结果(测试类和上一个相同):
只有Controller包和service包中创建的对象
注意: pom.xml中的
<maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target>
控制的是编译使用的JDK版本,如果此处使用的是JDK7,则MainConfig上无法添加多个@ComponentScan.
1.2.2自定义过滤器
在config包中创建MyTypeFilter类,并继承TypeFilter接口,写过滤条件.
public class MyTypeFilter implements TypeFilter { /** * * @param metadataReader:读取到的当前正在扫描的类的信息 * @param metadataReaderFactory:可以获取到其他任何类的信息 * @return * @throws IOException */ @Override public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException { //获取当前类注解的信息 AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata(); //获取当前扫描的类信息 ClassMetadata classMetadata = metadataReader.getClassMetadata(); String className = classMetadata.getClassName();//获取当前的类名 System.out.println("-->" + className); if (className.contains("er")) {//如果类名包含er return true;//被过滤器过滤 } return false;//不被过滤 } }
MainConfig中引入:
@ComponentScan(value="com.rg",includeFilters = { // @ComponentScan.Filter(type=FilterType.ANNOTATION,classes={Controller.class}), // @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,classes = {BookService.class}), @ComponentScan.Filter(type = FilterType.CUSTOM,classes = {MyTypeFilter.class}) }, useDefaultFilters = false) @Configuration //告诉Spring这是一个配置类 public class MainConfig { //给容器注册一个Bean;类型为返回值的类型,id默认是用方法名作为id @Bean("person") //修改方法名称 public Person person(){ return new Person("lisi",20); } }
测试结果:
第一部分是符合条件的类名称,第二部分是存入到IOC容器中的对象的名称.
2.@Scope
MainConfig:
//默认是单实例的 /** * * @see ConfigurableBeanFactory#SCOPE_PROTOTYPE * * @see ConfigurableBeanFactory#SCOPE_SINGLETON * * @see org.springframework.web.context.WebApplicationContext#SCOPE_REQUEST request * * @see org.springframework.web.context.WebApplicationContext#SCOPE_SESSION session * @return\ * @Scope:调整作用域 * prototype:多实例的:ioc容器启动并不会去调用方法创建对象放在容器中。 * 每次获取的时候才会调用方法创建对象; * singleton:单实例的(默认值):ioc容器启动会调用方法创建对象放到ioc容器中。 * 以后每次获取就是直接从容器(map.get())中拿, * request:同一次请求创建一个实例 * session:同一个session创建一个实例 * * 懒加载: * 单实例bean:默认在容器启动的时候创建对象; * 懒加载:容器启动不创建对象。第一次使用(获取)Bean创建对象,并初始化; * */ @Scope( ) @Configuration public class MainConfig2 { //给容器注册一个Bean;类型为返回值的类型,id默认是用方法名作为id @Bean("person") public Person person(){ System.out.println("给容器中添加Person..."); return new Person("lisi",20); } }
测试:
@Test public void test04(){ AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class); //System.out.println("IOC容器创建完成..."); //System.out.println("hahha嗷嗷嗷"); // Person person = (Person) applicationContext.getBean("person"); // Person person2 = (Person) applicationContext.getBean("person"); // System.out.println(person == person2); //当为默认时,结果为true,当为prototype结果为false. }
运行结果:
当修改为@Scope(“propotype”)时,会先创建IOC容器,然后每次获取才调方法,创对象.
注:此处会出现@Scope(“propotype”)失效的问题,解决办法还没有找到…
3.@Lazy
单实例bean:默认在容器启动的时候创建对象;
懒加载:容器启动不创建对象。第一次使用(获取)Bean创建对象,并初始化.
MainConfig
@Lazy @Scope @Configuration public class MainConfig2 { //给容器注册一个Bean;类型为返回值的类型,id默认是用方法名作为id @Bean("person") public Person person(){ System.out.println("给容器中添加Person..."); return new Person("lisi",20); } }
测试:
@Test public void test04(){ AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class); System.out.println("IOC容器创建完成..."); //System.out.println("hahha嗷嗷嗷"); Person person = (Person) applicationContext.getBean("person"); Person person2 = (Person) applicationContext.getBean("person"); System.out.println(person == person2); }
测试结果: