星星博客 »  > 

Spring入门之IOC

Spring的IOC

IOC的概念

IOC英文inversion of control叫控制反转,在spring中就是把对象的创建交给spring框架来处理。把创建和对象之间的调用过程交给Spring进行管理,可以减低代码耦合度。

原理

xml解析->工厂模式->反射

IOC接口

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依赖注入方式-->
<!--外部注入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:根据名称进行注入

@Qualifier(value = “”)

属性设置

@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;

相关文章