为什么要使用直接配置?
当然是便捷性,维护性强呀~
如果想要使用注解,在XML文件中需要什么配置?
##注解配置载入
<context:annotation-config/>
四个重要的注解
- @Required: 应用于set()方法
- @Autowired: 应用于set()方法,构造方法,属性
- @Qualifier: 指定确切的bean
- JSR-250 Annotations: 支持 JSR-250 的基础的注解,其中包括了 @Resource,@PostConstruct 和 @PreDestroy 注解。
1、@Required注解
Product.java
public class Product {
private String pid;
private String pname;
public Product() {
}
public Product(String pid, String pname) {
this.pid = pid;
this.pname = pname;
}
public String getPid() {
return pid;
}
@Required
public void setPid(String pid) {
this.pid = pid;
}
public String getPname() {
return pname;
}
@Required
public void setPname(String pname) {
this.pname = pname;
}
@Override
public String toString() {
return "Product{" +
"pid='" + pid + '\'' +
", pname='" + pname + '\'' +
'}';
}
}
Beans.xml
<context:annotation-config/>
<bean id="product" class="org.example.POJO.Product">
<property name="pid" value="p1233323"/>
<property name="pname" value="经典牛奶"/>
</bean>
输出结果
Product{pid='p1233323', pname='经典牛奶'}
你做了以上操作,你会发现,有没有@Required都不影响你的程序运行。
为什么会出现这样的情况呢?
@Required 主要是用来标注该set()方法必须使用XML文件中显式注入,不然会报错。
它就是这个作用,但是编辑器中也会自动识别XML文件中显式注入不完整,而产生错误高亮。
2、@Autowired注解
@Autowired就是自动装配,我们在前面已经讲了自动装配适用的场景就是引用了自定义类的地方,所以该注解也同样如此,并且指明了装配该区域,使得更加效率。
@Autowired用法
例如
在字段上
@Autowired
private Product product;
在set方法上
@Autowired
public void setProduct(Product product) {
this.product = product;
}
在构造方法上
@Autowired
public Sales(String sid, int price, Product product) {
this.sid = sid;
this.price = price;
this.product = product;
}
构造方法一定要在XML文件中,一定要配置好<constructor-arg />,否则会报异常。
所以我们可以意识到,Collection<Product>也同样适配@Autowired
3、@Qualifiler注解
首先理解Qualifier 的意思是 限定。
所以它的作用是限定一个bean类型进行装配
@Qualifiler通常会与@Autowired搭配使用,来限定采用哪一种同类型的bean
Sales.java
public class Sales {
private String sid;
private int price;
@Autowired
@Qualifier("product2")
private Product product;
public Sales(String sid, int price, Product product) {
this.sid = sid;
this.price = price;
this.product = product;
}
public Sales() {
}
public String getSid() {
return sid;
}
public void setSid(String sid) {
this.sid = sid;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
public Product getProduct() {
return product;
}
@Autowired
@Qualifier("product2")
public void setProduct(Product product) {
this.product = product;
}
@Override
public String toString() {
return "Sales{" +
"sid='" + sid + '\'' +
", price=" + price +
", product=" + product +
'}';
}
}
Beans.xml
<context:annotation-config/>
<bean id="sales" class="org.example.POJO.Sales">
<property name="price" value="251"/>
<property name="sid" value="sales100000"/>
</bean>
<bean id="product1" class="org.example.POJO.Product">
<property name="pid" value="p1"/>
<property name="pname" value="经典牛奶"/>
</bean>
<bean id="product2" class="org.example.POJO.Product">
<property name="pid" value="p2"/>
<property name="pname" value="奥利奥"/>
</bean>
输出结果
Sales{sid='sales100000', price=251, product=Product{pid='p2', pname='奥利奥'}}
4、JSR-250注释
- @PostConstruct: 替代XML中配置init-method
- @PreDestroy 替代XML中配置destory-method
- @Resource 指明使用哪一个bean,如果没有指定name,则默认为字段名或setter方法。
public class Sales{
@Resource(name="price")
private int price;
@Resource(name="product")
private Product product;
@Resource(name="product")
public void setProduct(Product product){
this.product = product;
}
}
Sales.java
public class Sales implements InitializingBean, DisposableBean {
private String sid;
private int price;
@Autowired
@Qualifier("product2")
private Product product;
public Sales(String sid, int price, Product product) {
this.sid = sid;
this.price = price;
this.product = product;
}
public Sales() {
}
public String getSid() {
return sid;
}
public void setSid(String sid) {
this.sid = sid;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
public Product getProduct() {
return product;
}
@Autowired
@Qualifier("product2")
public void setProduct(Product product) {
this.product = product;
}
@Override
public String toString() {
return "Sales{" +
"sid='" + sid + '\'' +
", price=" + price +
", product=" + product +
'}';
}
@PreDestroy
@Override
public void destroy() throws Exception {
System.out.println("Bean正在被销毁");
}
@PostConstruct
public void init(){
System.out.println("Bean正在被初始化");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("Bean已经创建成功");
}
}
输出结果
Bean正在被初始化
Bean已经创建成功
Sales{sid='sales100000', price=251, product=Product{pid='p2', pname='奥利奥'}}
Bean正在被销毁
5、基于Java的配置
重要的辅助注解
- @Configuration: 标记为Bean定义来源
- @Bean: 标记为注册成Spring应用程序上下文的Bean
User.java
public class User implements InitializingBean, DisposableBean {
private String uid;
private String uname;
public User() {
}
public User(String uid, String uname) {
this.uid = uid;
this.uname = uname;
}
public String getUid() {
return uid;
}
public void setUid(String uid) {
this.uid = uid;
}
public String getUname() {
return uname;
}
public void setUname(String uname) {
this.uname = uname;
}
@PostConstruct
public void init(){
System.out.println("Bean is going through init");
}
@PreDestroy
public void destroy(){
System.out.println("Bean will destroy now");
}
@Override
public String toString() {
return "User{" +
"uid='" + uid + '\'' +
", uname='" + uname + '\'' +
'}';
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("UserBean has created。");
}
}
UserConfig.java
@Configuration
public class UserConfig {
@Bean
public User getUser(){ //User作为class,getUser作为id
return new User();
}
}
等同于
<beans>
<bean id="getUser" class="org.example.User" />
</beans>
Main.java
public class Main {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(UserConfig.class); //通过注解配置类加载到ApplicationContext容器
User user = context.getBean(User.class); //因为配置为Bean时通过User作为id,所以需要User.class来获取对象
user.setUname("我是谁呢?");
System.out.println(user);
}
}
输出结果
Bean is going through init
UserBean has created。
User{uid='null', uname='我是谁呢?'}
注入Bean的依赖性
跟配置XML文件相同
@Configuration
public class AppConfig{
@Bean
public Foo foo(){
return new Foo(bar());
}
@Bean
public Bar bar(){
return new Bar();
}
}
等同于
<bean id="foo" class="Foo">
<property id="bar" ref="bar" />
</bean>
<bean id="bar" class="Bar" />
@import注解
作用: 允许集合到一个配置类中
Man.java
public class Man {
private int mid;
public int getMid() {
return mid;
}
public void setMid(int mid) {
this.mid = mid;
}
}
Female.java
public class Female {
private int fid;
public int getFid() {
return fid;
}
public void setFid(int fid) {
this.fid = fid;
}
}
ManConfig.java
@Configuration
public class ManConfig {
@Bean
public Man man(){
return new Man();
}
}
FemaleConfig.java
@Configuration
@Import(ManConfig.class)
public class FemaleConfig {
@Bean
public Female female(){
return new Female();
}
}
Main.java
public class Main {
public static void main(String[] args) {
//只需要引入最终的配置类集合,就能够通过反射机制获取对象
ApplicationContext context = new AnnotationConfigApplicationContext(UserConfig.class);
context = new AnnotationConfigApplicationContext(FemaleConfig.class);
Female female = context.getBean(Female.class);
female.setFid(12);
Man man = context.getBean(Man.class);
man.setMid(23);
System.out.println(female.getFid());
System.out.println(man.getMid());
}
}
生命周期回调
@Bean(initMethod = "init",destroyMethod = "destroy")
指定Bean的范围
@Bean
@Scope("prototype")
6、事件处理
什么是事件?
举个例子: ApplicationContext启动会有start事件,ApplicationContext结束会有stop事件
如何处理事件?
- 工具:ApplicationEvent类和ApplicationListener接口。
- 应用:一个bean实现ApplicationListener,则ApplicationEvent发布到ApplicationContext上时,该bean也能获取到。
标准事件
- ContextRefreshedEvent: 初始化或刷新时,该事件被发布,也可以通过ConfigurableApplicationContext.refresh()方法发生。
- ContextStartedEvent: 当使用ConfigurableApplicationContext.start()启动ApplicationContext时,该事件被发布,进行调查数据库或重启任何应用程序。
- ContextStoppedEvent: 当使用ConfigurableApplicationContext.stop()暂停ApplicationContext时,该事件被发布,进行清理工作。
- ContextClosedEvent: 当使用 ConfigurableApplicationContext 接口中的 close() 方法关闭 ApplicationContext 时,该事件被发布。一个已关闭的上下文到达生命周期末端;它不能被刷新或重启。
- RequestHandledEvent: 这是一个 web-specific 事件,告诉所有 bean HTTP 请求已经被服务。
注意: 由于 Spring 的事件处理是单线程的,所以如果一个事件被发布,直至并且除非所有的接收者得到的该消息,该进程被阻塞并且流程将不会继续。因此,如果事件处理被使用,在设计应用程序时应注意。
监听上下文事件
如何实现? bean实现ApplicationListener
- 步骤1: 创建监听事件配置文件 BStartEventHandler.java,BStopEventHandler.java
- 步骤2: 注册监听Bean Beans.xml
- 步骤3: 获取ConfigurableApplicationContext对象 Main.java
BStartEventHandler.java
public class BStartEventHandler implements ApplicationListener<ContextStartedEvent> {
@Override
public void onApplicationEvent(ContextStartedEvent event) {
System.out.println("the ApplicationContext Container start");
}
}
BStopEventHandler.java
public class BStopEventHandler implements ApplicationListener<ContextStoppedEvent> {
@Override
public void onApplicationEvent(ContextStoppedEvent event) {
System.out.println("the ApplicationContext Container stop");
}
}
Beans.xml
<context:annotation-config/>
<bean id="sales" class="org.example.POJO.Sales">
<property name="price" value="251"/>
<property name="sid" value="sales100000"/>
</bean>
<bean id="product1" class="org.example.POJO.Product">
<property name="pid" value="p1"/>
<property name="pname" value="经典牛奶"/>
</bean>
<bean id="product2" class="org.example.POJO.Product">
<property name="pid" value="p2"/>
<property name="pname" value="奥利奥"/>
</bean>
<bean id="bStartEventHandler" class="org.example.POJO.BStartEventHandler" />
<bean id="bStopEventHandler" class="org.example.POJO.BStopEventHandler" />
Main.java
public class Main {
public static void main(String[] args) {
ConfigurableApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
context.start();
Sales sales = (Sales) context.getBean("sales");
System.out.println(sales);
context.stop();
}
}
输出结果
Bean正在被初始化
Bean已经创建成功
the ApplicationContext Container start
Sales{sid='sales100000', price=251, product=Product{pid='p2', pname='奥利奥'}}
the ApplicationContext Container stop
7、自定义事件
如何定义事件?
- 步骤1: 创建ApplicationEvent继承类
- 步骤2: 创建ApplicationEventPublisherAware接口实现类
- 步骤3: 创建监听类
- 步骤4: 声明监听Bean
- 步骤5: 使用发布类
CustomEvent.java
public class CustomEvent extends ApplicationEvent{
public CustomEvent(Object source) {
super(source);
}
public String toString(){
return "My Custom Event";
}
}
CustomEventPublisher.java
public class CustomEventPublisher
implements ApplicationEventPublisherAware {
private ApplicationEventPublisher publisher;
//获取发布器
public void setApplicationEventPublisher(ApplicationEventPublisher publisher){
this.publisher = publisher;
}
public void publish() {
CustomEvent ce = new CustomEvent(this); //获取事件
publisher.publishEvent(ce); //发布事件
}
}
MainApp.java
public class MainApp {
public static void main(String[] args) {
ConfigurableApplicationContext context =
new ClassPathXmlApplicationContext("Beans.xml");
CustomEventPublisher cvp =
(CustomEventPublisher) context.getBean("customEventPublisher");
cvp.publish();
}
}
Beans.xml
<bean id="customEventHandler"
class="com.tutorialspoint.CustomEventHandler"/>
<bean id="customEventPublisher"
class="com.tutorialspoint.CustomEventPublisher"/>