Spring的IOC
IOC的概念
IOC英文inversion of control叫控制反转,在spring中就是把对象的创建交给spring框架来处理。把创建和对象之间的调用过程交给Spring进行管理,可以减低代码耦合度。
原理
xml解析->工厂模式->反射
IOC接口
首先要导入bean,context,core,expression依赖
BeanFatory
为beanFatory的子类,加载配置文件的时候不会创建配置文件里面的bean对象,使用的时候才会创建
ApplicationContext
为beanFatory的子类,加载配置文件的时候会创建配置文件里面的bean对象。
实现类
ClassPathXmlApplicationContext:在classpath路径下。
FileSystemPathXmlApplicationContext:在系统路径下。
xml文件的基本配置
首先这里要注意的一点是配置bean的属性,该属性必须要有set方法。
当然也可以用构造器的形式来配置属性。
Book.class
public class Book {
private String sn;
private String name;
private BigDecimal price;
private String author;
}
BookKind.class
public class BookKind {
private String kindName;
private Book book;
}
配置属性无对象的bean
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 外部bean-->
<!--使用p名称空间赋值 要添加规范xmlns:p="http://www.springframework.org/schema/p"-->
<bean id="book" class="com.hn.entity.Book" p:author="zz" p:name="牛逼">
<property name="sn">
<!--对值赋null-->
<null></null>
</property>
<property name="price">
<!-- 用CDATA的方式配置属性值,因为xml文件中特殊字符需要转义,使用其就不用了-->
<value><![CDATA[100.0]]></value>
</property>
</bean>
配置属性有对象的bean
<!--DI依赖注入方式-->
<!--<constructor-arg>注入-->
<!--外部注入bean-->
<bean id="bookKind" class="com.hn.entity.BookKind">
<property name="kindName" value="计算机书"></property>
<property name="book" ref="book"></property>
</bean>
<!--内部注入-->
<bean id="bookKind" class="com.hn.entity.BookKind">
<property name="kindName" value="计算机书"></property>
<property name="book">
<bean id="book" class="com.hn.entity.Book">
<property name="author" value="皓楠"></property>
<property name="price" value="100"></property>
</bean>
</property>
</bean>
<!--级联赋值-->
<bean id="bookKind" class="com.hn.entity.BookKind">
<property name="kindName" value="计算机书"></property>
<property name="book" ref="book"></property>
<!--要有get方法-->
<property name="book.name" value="编程思想"></property>
</bean>
Card.class
public class Card {
private Integer id;
private String name;
}
Stu.class
public class Stu {
private String[] courses;
private List<String> list;
private Map<String,String> map;
private Set<String> set;
private List<Card> cards;
}
配置属性有集合的bean
<!--数组,集合,map 为String案例-->
<bean id="stu" class="com.hn.entity.Stu">
<!--数组-->
<property name="courses">
<!--也可以用array-->
<list>
<value>java</value>
<value>python</value>
</list>
</property>
<!--list-->
<property name="list">
<list>
<value>zz</value>
<value>xx</value>
</list>
</property>
<!--map-->
<property name="map">
<map>
<entry key="JAVA" value="java"></entry>
<entry key="PHP" value="phn"></entry>
</map>
</property>
<!--set-->
<property name="set">
<set>
<value>gg</value>
<value>gg</value>
</set>
</property>
<!--泛型为card的list-->
<property name="cards">
<list >
<!--外部注入-->
<ref bean="card"></ref>
<bean id="card2" class="com.hn.entity.Card">
<property name="id" value="2"></property>
<property name="name" value="银行卡"></property>
</bean>
</list>
</property>
</bean>
<bean id="card" class="com.hn.entity.Card">
<property name="id" value="1"></property>
<property name="name" value="校园卡"></property>
</bean>
<bean id="stu2" class="com.hn.entity.Stu">
<property name="cards">
<list>
<ref bean="card"></ref>
</list>
</property>
</bean>
</beans>
引用util空间实现list的外部注入
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
<util:list id="list">
<value>天天兄弟</value>
<value>好好学习</value>
<value>快乐</value>
</util:list>
<bean id="stu" class="com.hn.entity.Stu">
<property name="list" ref="list">
</property>
</bean>
</beans>
IOC操作Bean管理
Spring有两种类型的bean:
1.普通bean:在配置文件中定义bean类型就是返回类型。
2.工厂bean:在配置文件定义bean类型可以和返回类型不一样。
工厂bean的实现
class对象实现Factorybean接口即可。
public class MyFactory implements FactoryBean<Stu> {
@Override
public Stu getObject() throws Exception {
return new Stu();
}
@Override
public Class<?> getObjectType() {
return null;
}
@Override
public boolean isSingleton() {
return FactoryBean.super.isSingleton();
}
}
不需要实现接口的bean工厂的调用
Resource resource=new ClassPathResource( "jdbc.xml" );
BeanFactory beanFactory=new XmlBeanFactory(resource );
JdbcTemplate jdbcTemplate = beanFactory.getBean( "JdbcTemplate", JdbcTemplate.class );
System.out.println(jdbcTemplate);
JdbcTemplate jdbcTemplate2 = beanFactory.getBean( "JdbcTemplate", JdbcTemplate.class );
System.out.println(jdbcTemplate2);
bean的作用域
在spring可以设置bean的实例为单实例还是多实例,默认为单实例。
配置xml的bean的socope属性
设置为prototype,既是是在ApplicationContext的方法下加载配置文件,也要getbean才会创建实例,相当于懒汉式。
<!--多实例-->
<bean id="stu" class="com.hn.entity.Stu" scope="prototype">
bean的生命周期
1、实例化对象。
2、调用set方法进行属性赋值。
3、调用init初始化方法,需要进行配置。
4、使用bean。
5、当容器关闭时,调用bean销毁方法,需要进行配置。
加上后置处理器后会有7步
1、实例化对象。
2、调用set方法进行属性赋值。
3、把bean的实例传递bean后置处理器
4、调用init初始化方法,需要进行配置。
5、把bean的实例传递bean后置处理器
6、使用bean。
7、当容器关闭时,调用bean销毁方法,需要进行配置。
后置处理器的创建
public class BeanPost implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("第三步 前置初始化方法");
return BeanPostProcessor.super.postProcessBeforeInitialization( bean, beanName );
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("第五步 后置初始化方法");
return BeanPostProcessor.super.postProcessAfterInitialization( bean, beanName );
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="life" class="com.hn.entity.BeanLife" init-method="init" destroy-method="destroy">
<property name="s" value="s"/>
</bean>
<bean id="post" class="com.hn.entity.BeanPost"></bean>
</beans>
public class BeanLife {
private String s;
public BeanLife(){
System.out.println("第一步无参数构造方法");
}
public void setS(String s) {
System.out.println("第二步 调用Set方法");
this.s = s;
}
public void init(){
System.out.println("第四步 调用初始化方法");
}
public void destroy(){
System.out.println("第七步 调用销毁方法");
}
}
@Test
public void t() {
ApplicationContext context=new ClassPathXmlApplicationContext("beanlife.xml");
BeanLife beanLife = context.getBean( "life", BeanLife.class );
System.out.println("第六步 使用bean");
System.out.println( beanLife );
//关闭
((ClassPathXmlApplicationContext)context).close();
}
xml自动装配
概念:根据指定装配规则(属性名称或者属性类型),spring自己将匹配的属性进行诸如。
bean标签属性autowrite
byName:根据名称进行自动装配
byType:根据类型进行自动装配
不管是这两个的哪一个,实际使用情况都很少,因为他们是根据xml别的bean里面的id和class匹配该bean的property。
外部属性文件(druid的配置)
例子:配置druid
需引入名称空间context
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!--内部-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql:///testtest"></property>
<property name="username" value="root"></property>
<property name="password" value="root"></property>
</bean>
<!--外部-->
<context:property-placeholder location="jdbc.properties"/>
<bean id="dataSourceExtern" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${mysql.driverClassName}"></property>
<property name="url" value="${mysql.url}"></property>
<property name="username" value="${mysql.username}"></property>
<property name="password" value="${mysql.password}"></property>
</bean>
</beans>
注解实现
1、@Component
2、@Service
3、@Controller
4、@Repository
*功能一样大的,都可以来创建bean实例,主要用来区分。
示例:
第一步
需要引入依赖aop.jar
第二步
开启组件扫描
需引入名称空间context
配置要扫描的包名,可以用逗号隔开。
<context:component-scan base-package="com.hn.entity,com.hn.factorybean"></context:component-scan>
第三步
然后就能在对应的实体类增加注解了,注解设置value,对应的bean的id,若不配置则默认为类名称加首字母小写。
扫描配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!--配置use-default为false,include-filter配置只扫描Component-->
<context:component-scan base-package="com.hn.entity,com.hn.factorybean" use-default-filters="false">
<!-- -->
<context:include-filter type="annotation" expression="org.springframework.stereotype.Component"/>
</context:component-scan>
<!--exclude-filter配置只扫描除Controller注解以外的类-->
<context:component-scan base-package="com.hn.entity,com.hn.factorybean" use-default-filters="false">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
</beans>
对属性进行注入
第一种方法:@autowrited:根据类属性类型实现自动装配
public interface UserDao {
public void add();
}
@Repository
public class UserDaoImpl implements UserDao{
@Override
public void add() {
System.out.println("userdao .....add");
}
}
@Service
public class UserServiceImpl {
@Autowired
private UserDao userDao;
public void add(){
userDao.add();
System.out.println( "service ....add");
}
@Test
public void p(){
ApplicationContext context= new ClassPathXmlApplicationContext("annotation.xml");
UserServiceImpl userServiceImpl = context.getBean( "userServiceImpl", UserServiceImpl.class );
userServiceImpl.add();
}
}
第二种方法@Qualifier:根据名称进行注入
注意上面要加@Autowired
@Qualifier(value = “”)
属性设置
@Autowired
@Qualifier(value = "UserDao1")
private UserDao userDao;
实现类的bean注解配置名称
@Repository(value = "UserDao1")
public class UserDaoImpl implements UserDao{
第三种方法:@Resource即可通过名称也能通过属性类型
@Resource默认为属性类型
@Resource(name="")根据bean名称
注意:@Resource是javax包中的注解,不是spring的。
第四种方法:@Value普通属性类型的注入
例如:
@Value( "hn" )
private String name;
@Value( "101" )
private int num;