Spring支持用注解配置Bean,更简便。
上面的组件,是根据实际情况配的。比如写的一个类,是做业务处理的,那就用注解@Service表示服务层组件,以此类推。将整体分成不同部分。
要在xml加入context命名空间
1 <!-- 指定Spring IOC容器扫描的包 --> 2 <context:component-scan base-package="package com.guigu.spring.beans.annotation"></context:component-scan>
这样,就表示要自动扫描 基类包的类以及子包中的类。类中有注解,就会被管理
例子:
目录结构如下,第一个annotation包为要扫描的包,有下面三个子包:controller、repository、service
类里面都是一个简单的注解和一个方法:
1 //TestObject.java 2 package com.guigu.spring.beans.annotation; 3 4 import org.springframework.stereotype.Component; 5 6 @Component 7 public class TestObject { 8 9 }
1 //UserController.java 2 package com.guigu.spring.beans.annotation.controller; 3 import org.springframework.stereotype.Controller; 4 5 @Controller 6 public class UserController { 7 8 public void execute(){ 9 System.out.println("UserController execute..."); 10 } 11 }
1 //UserRepository.java 2 package com.guigu.spring.beans.annotation.repository; 3 public interface UserRepository { 4 5 void save(); 6 } 7 8 //UserRepositoryImpl.java 继承 UserRepository 9 package com.guigu.spring.beans.annotation.repository; 10 import org.springframework.stereotype.Repository; 11 12 @Repository("userRepository"); 13 public class UserRepositoryImpl implements UserRepository { 14 15 @Override 16 public void save() { 17 System.out.println("UserRepositoryImpl Save..."); 18 } 19 20 }
写一个继承,为了说明注解命名可以更改,这里改成了userRepository,否则是默认的userRepositoryImpl,下面讲。
1 //UserService.java 2 package com.guigu.spring.beans.annotation.service; 3 4 import org.springframework.stereotype.Service; 5 6 @Service 7 public class UserService { 8 9 public void add(){ 10 System.out.println("UserService add..."); 11 } 12 }
xml最上面已经配置,最后main函数:
1 package com.guigu.spring.beans.annotation; 2 3 import org.springframework.context.ApplicationContext; 4 import org.springframework.context.support.ClassPathXmlApplicationContext; 5 6 import com.guigu.spring.beans.annotation.controller.UserController; 7 import com.guigu.spring.beans.annotation.repository.UserRepository; 8 import com.guigu.spring.beans.annotation.service.UserService; 9 10 public class Main { 11 12 public static void main(String[] args) { 13 14 ApplicationContext ctx =new ClassPathXmlApplicationContext("beans-annotation.xml"); 15 TestObject to = (TestObject) ctx.getBean("testObject"); 16 System.out.println(to); 17 UserController userController=(UserController) ctx.getBean("userController"); 18 System.out.println(userController); 19 UserService userservice=(UserService) ctx.getBean("userservice"); 20 System.out.println(userservice); 21 UserRepository userRepository=(UserRepository) ctx.getBean("userRepository"); 22 System.out.println(userRepository); 23 } 24 25 }
输出如下:说明对象被创建了
xml里面没有bean,那main函数怎么获取Bean呢?
就是用最上面图中蓝色字体。Spring默认命名,名字是它的类名第一个字符小写。如:
UserService.java类中类名是UserService ,获取bean默认名字就是userService
也可以更改,如上面的UserRepositoryImpl类,用了@Repository("userRepository"),表示bean名字为userRepository
在xml中,有一些属性和节点:
resource-pattern:只扫描特定文件
context:include-filter: 子节点表示要包含的组件
context:exclude-filter: 子节点表示要排除在外的组件
1 <!-- 可以通过resource-pattern指定扫描的资源 --> 2 <context:component-scan base-package="package com.guigu.spring.beans.annotation" 3 resource-pattern="repository/*.class"> 4 </context:component-scan> 5
这样,只会扫描repository包下的类,如果main函数中,还要调用其他类,报错。只能调用repository包下的类。
1 <!-- context:exclude-filter 子节点指定排除哪些指定表达式的组件 --> 2 <context:component-scan base-package="package com.guigu.spring.beans.annotation"> 3 <context:exclude-filter type="annotation" expression="package com.guigu.spring.beans.annotation.repository"/> //type类型后面看 4 </context:component-scan> 5
这表示不扫描repository子包的文件,若main函数中调用它们,会抛异常
1 <!-- context:include-filter 子节点指定包含哪些指定表达式的组件, 该子节点需要use-default-filters配合使用 --> 2 <context:component-scan base-package="package com.guigu.spring.beans.annotation" 3 use-default-filters="false"> 4 <context:include-filter type="annotation" 5 expression="package com.guigu.spring.beans.annotation"/> 6 </context:component-scan>
注意,use-default-filters默认自动扫描全部,要设置成false不自动扫描,才能实现只扫描部分的功能。
<context:include-filter>和<context:exclude-filter>子节点支持多种类型的过滤表达式:
类别 | 示例 | 说明 |
annotation | com.yl.XxxAnnotation | 所有标注了XxxAnnotation的类,该类型采用目标类是否标注了某个注解进行过滤 |
assinable | com.yl.XxxService | 所有继承或扩展XxxService的类,该类型采用了目标类是否继承或扩展某个特定类进行过滤 |
aspectj | com.yl.*Service | 所有类名义Service结束的类及继承或扩展它们的类,该类型采用AspectJ表达式进行过滤 |
regex | com.yl.anno.* | 所有com.yl.anno包下的类。该类型采用正则表达式,根据类的类名进行过滤 |
custom | com.yl.XxxTypeFilter | 采用XxxTypeFilter通过代码的方式定义过滤原则。该类必须实现org.springframewor |
@Autowired:自动装配具有兼容类型的单个bean属性。可以对类成员变量、方法及构造函数进行标注,完成自动装配的工作。 通过 @Autowired的使用来代替set方法。(property 属性通过调用setter方法进行赋值)
意思就是用它,可以代替xml中的<property name="car" ref="car"> 这样的引用赋值。自动创建bean。
例子:Person类有Car对象,不用 自动装配
1 //Person类 2 public class Person { 3 private Car car; 4 5 public Car getCar() { 6 return car; 7 } 8 public void setCar(Car car) { 9 this.car = car; 10 } 11 }
1 //Car类 2 public class Car { 3 private String brand; 4 private double price; 5 6 public void setBrand(String brand) { 7 this.brand = brand; 8 } 9 public void setPrice(double price) { 10 this.price = price; 11 } 12 }
xml
1 <bean id="person" class="com.guigu.spring.bean.Person"> 2 <property name="car" ref="car"/> 3 </bean> 4 <bean id="car" class="com.guigu.spring.bean.Car"> 5 <property name="brand" value=" aodi"/> 6 <property name="price" value="200000"/> 7 </bean>
main
1 ApplicationContext context = new ClassPathXmlApplicationContext("autowired.xml"); 2 Person person=(Person)ctx.getBean("person"); 3 System.out.println(person);
这是之前的做法。
@Autowired自动装配的方法
查了一下,在之前版本的Spring中,要使用@Autowired,要在xml写上这一行代码才行
1 <!-- 该 BeanPostProcessor 将自动对标注 @Autowired 的 Bean 进行注入 --> 2 <bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>
但现在spring4,<context:component-scan>自动注册AutowiredAnnotationBeanPostProcessor实例,可以使用@Autowired和@Resource、和@Inject注解(一般用@Autowired)
所以,如果使用了<context:component-scan>,就不用额外注册,不然还是要
1 //Person类 2 public class Person { 3 //@Aotuwired //自动根据xml配置实例car对象 4 private Car car; 5 6 }
1 <bean id="person" class="com.guigu.spring.bean.Person"> 2 //这里就不需要再写ref="car" 3 </bean> 4 <bean id="car" class="com.guigu.spring.bean.Car"> 5 <property name="brand" value=" aodi"/> 6 <property name="price" value="200000"/> 7 </bean>
结果和不用 @Aotuwired一样,都可以
还可以写在setter上
1 //Person类 2 public class Person { 3 private Car car; 4 //@Aotuwired 5 public Car setCar(Car car){ 6 this.car=car; 7 } 8 }
回到注解上面的例子:
1 //UserController.java 2 package com.guigu.spring.beans.annotation.controller; 3 import org.springframework.stereotype.Controller; 4 5 @Controller 6 public class UserController { 7 8 public void execute(){ 9 System.out.println("UserController execute..."); 10 } 11 }
1 // main函数 2 public class Main { 3 4 public static void main(String[] args) { 5 private UserController userController; 6 ApplicationContext ctx =new ClassPathXmlApplicationContext("beans-annotation.xml"); 7 userController.execute(); // 报错
8 }
9 }
在main函数声明userController然后直接调用它的方法,这样显然不行,因为userController都还没有创建,这时用@Autowired就很简单
1 // main函数 2 public class Main { 3 4 public static void main(String[] args) { 5 //@Autowired 6 private UserController userController; 7 ApplicationContext ctx =new ClassPathXmlApplicationContext("beans-annotation.xml"); 8 userController.execute();//不报错 9 } 10 }
这样,就自动配置创建了userController对象,可以直接使用
注意①:@Autowired要想成功配置,得先扫描得到,就是UserController类一定要能被扫描到。
注意②:@Autowired遇到相同两个类
1 //UserRepository 2 package com.guigu.spring.beans.annotation.repository; 3 public interface UserRepository { 4 5 void save(); 6 } 7 8 //UserRepositoryImpl 继承 UserRepository 9 package com.guigu.spring.beans.annotation.repository; 10 import org.springframework.stereotype.Repository; 11 12 @Repository("userRepository"); //这里 13 public class UserRepositoryImpl implements UserRepository { 14 15 @Override 16 public void save() { 17 System.out.println("UserRepositoryImpl Save..."); 18 } 19 //UserRepositoryImpl2 继承 UserRepository 20 @Repository 21 public class UserRepositoryImpl2 implements UserRepository { 22 23 @Override 24 public void save() { 25 System.out.println("UserRepositoryImpl2 Save..."); 26 } 27 }
1 // main函数 2 public class Main { 3 4 public static void main(String[] args) { 5 //@Autowired 6 private UserRepository userRepository ; 7 ApplicationContext ctx =new ClassPathXmlApplicationContext("beans-annotation.xml"); 8 userRepository .save(); 9 } 10 }
main函数中有@Autowired,自动创建对象,但UserRepository 类却有两个接口,它要去创建哪一个呢?
:默认情况下,若有两个,去找名字相同的,就是还没实例的这个userRepository ,若找到和它名字一样的,上面 @Repository("userRepository"); 写了名字,那就找它了。
若不是这样写@Repository("userRepository");而是 @Repository(),那就报错了。
注意③:解决②的另一个方法
若@Repository("userRepository");改成@Repository(),main函数会报错。
改一下main函数
1 // main函数 2 public class Main { 3 4 public static void main(String[] args) { 5 //@Autowired 6 //Qualifier("userRepositoryImpl ") 7 private UserRepository userRepository ; 8 ApplicationContext ctx =new ClassPathXmlApplicationContext("beans-annotation.xml"); 9 userRepository .save(); 10 } 11 }
用Qualifier("userRepositoryImpl ");表示去找userRepositoryImpl 实例,这样也解决了。