Spring工厂类介绍
-
UML类图
- bean加载过程 https://www.cnblogs.com/xrq730/p/6285358.html
- 传统工厂类实现(方法已过时,仅供参考)
@Test
/**
* 传统方式工厂类BeanFactory
*/
public void demo4(){
BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
UserService userService = (UserService) beanFactory.getBean("userService");
userService.sayHello();
}
Bean实例化的三种方式
- 在实例化其中之一的过程中,applicationContext.xml所有配置的bean都会被实例化。
第一种:采用无参数的构造方法的方式
- Bean1.java
package com.alan.ioc.demo2;
/**
* Bean的实例化的三种方式:采用无参数的构造方法的方式
*/
public class Bean1 {
//无参构造
public Bean1() {
System.out.println("Bean1被实例化了。。。");
}
}
- applicationContext.xml配置
- Test.java
@Test
/**
* 采用无参数的构造方法的方式
*/
public void demo1(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Bean1 bean1 = (Bean1) applicationContext.getBean("bean1");
}
第二种:采用静态工厂方式创建实例
- Bean2.java
package com.alan.ioc.demo2;
/**
* Bean的实例化三种方式:静态工厂实例化方式
*/
public class Bean2 {
}
- Bean2Factory
package com.alan.ioc.demo2;
/**
* Bean2的静态工厂
*/
public class Bean2Factory {
public static Bean2 createBean2(){
System.out.println("Bean2Factory的方法已经执行了。。。。");
return new Bean2();
}
}
- applicationContext.xml配置
- Test.java
@Test
/**
* 采用静态工厂方式实例化
*/
public void demo2(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Bean2 bean2 = (Bean2) applicationContext.getBean("bean2");
}
第三种:采用实例工厂方式创建实例
- Bean2.java
package com.alan.ioc.demo2;
/**
* Bean的实例化三种方式:实例工厂实例化
*/
public class Bean3 {
}
- Bean3Factory
package com.alan.ioc.demo2;
/**
* Bean3的实例工厂(与静态工厂的区别,没有static修饰符)
*/
public class Bean3Factory {
public Bean3 createBean3(){
System.out.println("Bean3Factory执行了。。。");
return new Bean3();
}
}
- applicationContext.xml配置
- Test.java
@Test
/**
* 采用实例工厂方式实例化
*/
public void demo3(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Bean3 bean3 = (Bean3) applicationContext.getBean("bean3");
}
Bean的常用配置
- id和name
1、id属性在IOC容器中必须是唯一的
2、如果Bean的名称中含有特殊字符(例如struts总的“/”),就要使用时name.
3、其实id和name功能基本是一致的 - class
用于设置一个类的完全路径名称,主要作用是IOC容器生成类的实例
Bean的作用域(scope属性)
- 默认情况下是单例模式
- 多例模式配置(整合struts需要使用)
Bean的生命周期
- xml配置
- Man.java
package com.alan.ioc.demo3;
public class Man {
//无参构造
public Man() {
System.out.println("Man被实例化了。。。");
}
public void setup(){
System.out.println("Man被初始化了。。。");
}
public void teardown(){
System.out.println("Man被销毁了。。。");
}
}
- Test.java
***
@Test
public void demo2(){
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Man man = (Man) applicationContext.getBean("man");
System.out.println(man);
applicationContext.close();
}
Spring容器中Bean的生命周期
1:Bean的建立(实例化):
容器寻找Bean的定义信息并将其实例化。(instantiate bean)
2:属性注入:
使用依赖注入,Spring按照Bean定义信息配置Bean所有属性
3:如果Bean实现BeanNameAware接口,则执行setBeanName():
如果Bean类有实现org.springframework.beans.BeanNameAware接口,工厂调用Bean的setBeanName()方法传递Bean的ID。 (获得bean的id(name))
4:如果Bean实现BeanFactoryAware接口,则执行setBeanFactory():
如果Bean类有实现org.springframework.beans.factory.BeanFactoryAware接口,工厂调用setBeanFactory()方法传入工厂自身。
5:如果存在BeanPostProcessors(后处理Bean),则执行ProcessBeforeInitialization()
如果有org.springframework.beans.factory.config.BeanPostProcessors和Bean关联,那么其postProcessBeforeInitialization()方法将被将被调 用。
6:如果Bean实现InitializingBean接口,则执行afterPropertiesSet():
如果Bean类已实现org.springframework.beans.factory.InitializingBean接口,则执行他的afterProPertiesSet()方法
7:Bean定义文件中定义init-method:
可以在Bean定义文件中使用"init-method"属性设定方法名称例如:
如果有以上设置的话,则执行到这个阶段,就会执行initBean()方法
8:BeanPostProcessors的ProcessaAfterInitialization()
如果有任何的BeanPostProcessors实例与Bean实例关联,则执行BeanPostProcessors实例的ProcessaAfterInitialization()方法
9:执行Bean类中自己定义的方法
10:如果Bean实现 DisposableBean接口,则执行destroy
11:Bean定义文件中定义destroy-method:
可以在Bean定义文件中使用"destroy-method"属性设定方法名称例如:
如果有以上设置的话,则执行到这个阶段,就会执行destoryBean()方法
代码实现十一个步骤
- Bean.java
package com.alan.ioc.demo3;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
public class Man implements BeanNameAware , ApplicationContextAware , InitializingBean, DisposableBean {
private String name;
//无参构造
public Man() {
System.out.println("第一步:Man被实例化了。。。");
}
public void setName(String name) {
System.out.println("第二步:设置属性");
this.name = name;
}
/**
* 使Spring知道创建这个Bean的名称(id)
* @param name (xml中ID的值)
*/
@Override
public void setBeanName(String name) {
System.out.println("第三步:设置Bean的名称"+ name);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println("第四步:了解工厂的信息");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("第六步:属性设置后执行");
}
public void setup(){
System.out.println("第七步:Man被初始化了。。。");
}
public void run(){
System.out.println("第九步:执行自身定义的业务方法");
}
@Override
public void destroy() throws Exception {
System.out.println("第十步:执行Spring的销毁方法");
}
public void teardown(){
System.out.println("第十一步:Man被销毁了。。。");
}
}
- MyBeanPostProcessor.java
package com.alan.ioc.demo3;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
/**
* Spring中所有的bean都会执行此类中的方法
*/
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("第五步:初识化前方法");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("第八步:初始化后方法");
return bean;
}
}
- applicationContext.xml
BeanPostProcessor的作用
实例化时对类进行一些增强操作
package com.alan.ioc.demo3;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* Spring中所有的bean都会执行此类中的方法
*/
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("第五步:初识化前方法");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("第八步:初始化后方法");
//只对UserDao进行处理
if("userDao".equals(beanName)){
//产生代理
Object proxy = Proxy.newProxyInstance(bean.getClass().getClassLoader(), bean.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if("save".equals(method.getName())){
System.out.println("权限校验==================");
return method.invoke(bean,args);
}
return method.invoke(bean,args);
}
});
return proxy;
}else {
return bean;
}
}
}
Spring属性注入
第一种 构造方法属性注入(demo4)
- 通过构造方法注入Bean的属性值或依赖的对象,它保证了Bean实例在实例化后就可以使用。
- 构造器注入在
元素里声明的属性
- User.java
package com.alan.ioc.demo4;
public class User {
private String name;
private Integer age;
//带参构造
public User(String name,Integer age){
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
- test.java
package com.alan.ioc.demo4;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class SpringDemo4 {
@Test
public void demo1(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
User user = (User) applicationContext.getBean("user");
System.out.println(user);
}
}
第二种 set方法属性注入,经常使用(demo4)
- 通过
设置注入的属性 ref 传入对象 - Person.java
package com.alan.ioc.demo4;
public class Person {
private String name;
private Integer age;
private Cat cat;
//getter和setter方法
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 Cat getCat() {
return cat;
}
public void setCat(Cat cat) {
this.cat = cat;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", cat=" + cat +
'}';
}
}
- Cat.java
package com.alan.ioc.demo4;
public class Cat {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Cat{" +
"name='" + name + '\'' +
'}';
}
}
- xml
- test.java
@Test
public void demo2(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Person person = (Person) applicationContext.getBean("person");
System.out.println(person);
}
第三种 p名称空间方法属性注入
- xml
第四种 Spel方式属性注入
- Product.java
package com.alan.ioc.demo4;
public class Product {
private String name;
private Double price;
private Category category;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
public Category getCategory() {
return category;
}
public void setCategory(Category category) {
this.category = category;
}
@Override
public String toString() {
return "Product{" +
"name='" + name + '\'' +
", price=" + price +
", category=" + category +
'}';
}
}
- Category.java
package com.alan.ioc.demo4;
public class Category {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Category{" +
"name='" + name + '\'' +
'}';
}
}
- ProductInfo.java
package com.alan.ioc.demo4;
public class ProductInfo {
public Double calculatePrice(){
return Math.random() * 199 ;
}
}
- applicationContext.xml
- Test.java
@Test
public void demo3(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Product product = (Product) applicationContext.getBean("product");
System.out.println(product);
}
复杂类型属性注入(数组、集合等 demo5)
aaa
bbb
ccc
111
222
333
ddd
eee
fff
alan
alan
使用注解进行Bean管理
- xml
- UserService.java
package com.alan.demo1;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
/**
* Spring的Bean管理的注解方式
* 相当于在xml配置
*/
//@Component("userService")
@Service("userService")
public class UserService {
public String sayHello(String name){
return "hello "+name;
}
}
- Test.java
package com.alan.demo1;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class SpringDemo1 {
@Test
public void demo1(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = (UserService) applicationContext.getBean("userService");
System.out.println(userService.sayHello("alan"));
}
}
属性注入注解方式实现
package com.alan.demo1;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
/**
* Spring的Bean管理的注解方式
* 相当于在xml配置
*/
//@Component("userService")
@Service("userService")
public class UserService {
@Value("米饭")
private String something;
@Autowired
@Qualifier("userDao")
//@Resource(name = "userDao") //相当于上面两行注解
private UserDao userDao;
public String sayHello(String name){
return "hello "+name;
}
public void eat(){
System.out.println("eat:"+ something);
}
public void save(){
System.out.println("UserService中保存用户。。。");
userDao.save();
}
}
package com.alan.demo2;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
@Component("bean1")
public class Bean1 {
@PostConstruct
public void init(){
System.out.println("initBean...");
}
public void say(){
System.out.println("say....");
}
@PreDestroy
public void destory(){
System.out.println("destoryBean...");
}
}
- 两种方式同时使用xml需要填写