SpringFramework(三) 控制反转IOC

IOC是什么

IOC:控制反转, 是一种设计思想。在Java开发中,Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。

//传统方式
public class Demo{
  // 手动创建对象 new
  User user = new User();
  void test(){
    user.speak();
  }
}
// IOC
public class Demo{
  // User通过容器来进行管理,注入
  @Autowired
  User user;
  void test(){
  	user.speak();
  }
}	

为什么使用IOC

日常开发过程中推荐面向抽象编程,面向抽象变成会产生类的依赖,这是我们就需要一个管理的容器来管理这些依赖,同样,类的产生也就交给了容器。

实际使用场景:

事务使用:假如一个方法需要进行事务管理,那么我们正常操作是自己手动进行事务管理,但这样操作的缺点是。

  1. 假如说这个方法,有的方法调用需要开启事务,而有的方法不需要开启,则无法控制。
  2. 违反单一指责,将事务参杂在业务逻辑中
public class OrderService {
	public void placeOrder(){
		// 开启事务
		// 操作过程
		// 关闭事务
	}
}

如果使用容器管理,即可通过容器来进行管理事务。

@Service
public class OrderService {
	public void placeOrder(){
		// 操作过程
	}
}
public class Commodity{
  @Autowired
  OrderService service;
    
  @Transaction
  public void buyComm(){
    service.placeOrder()}
}

依赖注入的方式

两种注入方式:

  1. 构造方法注入 Constructor-based Dependency Injection
package x.y;

public class ThingOne {

    public ThingOne(ThingTwo thingTwo, ThingThree thingThree) {
        // ...
    }
}
<beans>
    <bean id="beanOne" class="x.y.ThingOne">
        <constructor-arg ref="beanTwo"/>
        <constructor-arg ref="beanThree"/>
    </bean>
    <bean id="beanTwo" class="x.y.ThingTwo"/>
    <bean id="beanThree" class="x.y.ThingThree"/>
</beans>
  1. set方法注入 Setter-based Dependency Injection
public class ExampleBean {

    private AnotherBean beanOne;

    private YetAnotherBean beanTwo;

    private int i;

    public void setBeanOne(AnotherBean beanOne) {
        this.beanOne = beanOne;
    }

    public void setBeanTwo(YetAnotherBean beanTwo) {
        this.beanTwo = beanTwo;
    }

    public void setIntegerProperty(int i) {
        this.i = i;
    }
}
<bean id="exampleBean" class="examples.ExampleBean">
    <!-- setter injection using the nested ref element -->
    <property name="beanOne">
        <ref bean="anotherExampleBean"/>
    </property>

    <!-- setter injection using the neater ref attribute -->
    <property name="beanTwo" ref="yetAnotherBean"/>
    <property name="integerProperty" value="1"/>
</bean>

<bean id="anotherExampleBean" class="examples.AnotherBean"/>
<bean id="yetAnotherBean" class="examples.YetAnotherBean"/>

自动装配

自动装配的4种方式

  1. no
  2. bytype
  3. byname
  4. constructor

Spring懒加载

懒加载:顾名思义,项目启动时并未初始化,而是使用时才初始化。

<bean id="lazy" class="com.something.ExpensiveToCreateBean" lazy-init="true"/>
<bean name="not.lazy" class="com.something.AnotherBean"/>
@Lazy
@Service
public class ExampleBean {
}

Bean的作用域

  1. singleton 单例 (default)
  2. prototype 原型
  3. request
  4. session
  5. application
  6. websocket

问题:当Singleton中引用prototype的bean时,会引发什么问题?

答:prototype会失去意义,在Singleton单例的对象中,引入的prototype只会初始化一次

@Scope("singleton")
@Repository
public class SingletonDao {
	@Autowired
	PrototypeDao prototypeDao;

	public PrototypeDao getPrototypeDao() {
		return prototypeDao;
	}
}

@Scope("prototype")
@Repository
public class PrototypeDao {
}
@Configuration
@ComponentScan("mine.test")
public class App {
	public static void main(String[] args) {
		ApplicationContext context=new AnnotationConfigApplicationContext(App.class);
		for (int i = 0; i < 3; i++) {
			SingletonDao dao = context.getBean(SingletonDao.class);
			System.out.println("SingletonDao:"+dao.hashCode());
			System.out.println("PrototypeDao:"+dao.getPrototypeDao().hashCode());
		}
	}
}
/* 结果:可见原型未起作用
SingletonDao:1849433705
PrototypeDao:411631404
SingletonDao:1849433705
PrototypeDao:411631404
SingletonDao:1849433705
PrototypeDao:411631404
*/

如何解决此问题?官网给出两种答案。

  1. 实现ApplicationContextAware
  2. 使用LookUp
// 方法一:实现ApplicationContextAware
@Scope("singleton")
@Repository
public class SingletonDao  implements ApplicationContextAware {
	private ApplicationContext applicationContext;
  
	public PrototypeDao getPrototypeDao() {
		return applicationContext.getBean(PrototypeDao.class);
	}
	public void setApplicationContext(
			ApplicationContext applicationContext) throws BeansException {
		this.applicationContext = applicationContext;
	}
}

// 方法二: LookUp
@Scope("singleton")
@Repository
public abstract class SingletonDao   {
	@Lookup
	public abstract PrototypeDao getPrototypeDao();
}

SpringBean生命周期的回调

SpringBean的回调方式

  1. 实现InitializingBean &DisposableBean
  2. @PostConstruct & @PreDestroy注解
@Service  //方式一:实现接口
public class AnotherExampleBean implements InitializingBean,DisposableBean {
   AnotherExampleBean(){
     // Construction method
   } 
   @Override
    public void afterPropertiesSet() {
        // do some initialization work
    }
    @Override
    public void destroy() {
        // do some destruction work (like releasing pooled connections)
    }
}
@Service //方式二:注解方式
public class AnotherExampleBean {
	AnotherExampleBean(){
     // Construction method
   } 
  @PostConstruct`
	public void init() {
        // do some initialization work
    }
    @PreDestroy
	public void destroy() {
        // do some destruction work (like releasing pooled connections)
    }
}

课外知识

Spring编程风格有三种

  1. annotation-base (注解方式)@AspectJ support
  2. Schema-based App (XML方式)
  3. Java-base

@Autowired和@Resource的区别?

  1. @Autowired使用byType的方式,如果未找到对应类型,采用byName(属性名,非set方法)注入

  2. @Resource默认采用byName(属性名,非set方法)注入,如果未找到对应名称,则去找byType的方式

@Component、@Repository、@Service和@Controller的区别?

  1. @Component是任何Spring管理组件的通用原型
  2. 相当于类型的区分
  3. 未来可能重大更新,建议按照对应的规则使用
    在这里插入图片描述

如何解决注入找到多个Bean对象的问题?

  1. @Primary
  2. @Qualifier
// 定义接口
public interface MovieCatalog {
}
// 方式一:多实现使用@Primary
@Configuration
public class MovieConfiguration {
    @Primary
	  @Bean("main")
    public MovieCatalog firstMovieCatalog() { ... }
    @Bean
    public MovieCatalog secondMovieCatalog() { ... }
}
// 方式二:注入时使用@Qualifier
public class MovieRecommender {
    @Autowired
    @Qualifier("main")
    private MovieCatalog movieCatalog;
}

如何在获取Bean对象?

  1. 实现ApplicationContextAware
@Scope("singleton")
@Repository
public class SingletonDao  implements ApplicationContextAware {
	private ApplicationContext applicationContext;
  
	public PrototypeDao getPrototypeDao() {
		return applicationContext.getBean(PrototypeDao.class);
	}
	public void setApplicationContext(
			ApplicationContext applicationContext) throws BeansException {
		this.applicationContext = applicationContext;
	}
}

Java中循环引用,GC如何回收?

待补充…

Spring如何解决循环引用问题?

简单来说,先有一层缓存,将bean存起来后,再进行相互引用。

解析,待补充…

官方文档:https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值