JavaEE学习日志(八十九): spring注解开发详解

JavaEE学习日志持续更新----> 必看!JavaEE学习路线(文章总汇)

Spring注解开发

注解开发入门

1、引入依赖
2、配置文件

  • 头文件增加命名空间和约束
  • 开启注解
 <context:component-scan base-package="包名"></context:component-scan>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       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
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
">
    <!--
        开启注解,指定扫描的包:context:component-scan
        引入context名称空间,引入约束

        base-package:指定要扫描的包,扫描的是包和其子包
    -->
    <context:component-scan base-package="com.itheima"></context:component-scan>
</beans>

3、在需要创建的类上添加注解@Component

package com.itheima.dao.impl;

import com.itheima.dao.UserDao;
import org.springframework.stereotype.Component;

@Component
public class UserDaoImpl implements UserDao {
}

4、测试

@Test
    public void test(){
        //创建容器对象
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
        //获取对象
        UserDao userDao = ac.getBean(UserDao.class);
        System.out.println(userDao);
    }

Component注解

@Component标志在类上,不能用在方法上
作用:只要扫描了包,就会创建对象

1、衍生了三个子注解

  • @Controller一般用于web层
  • @Service一般用于业务层
  • @Repository一般用于持久层

作用:三个的作用和@Component都是一样的,但最好别混用。

2、@Component中有个属性value=""
可以用于指定名字,默认的名称是简单类名首字母小写
(UserServiceImpl->userServiceImpl)

@Component("userService")

相当于xml中

<bean id="userService" class="全限类名"></bean>

自动注入@Autowired

如果想在UserService中调用UserDao,则只需要加上@Autowired注解即可。

可以标记在属性或set方法上,如果标记在属性上,可以没有set方法

@Service("userService")
public class UserServiceImpl implements UserService {
    @Autowired
    UserDao userDao;

    public void print(){
        userDao.print();
    }
}

特点:自动按照类型注入
流程:当属性或方法(set方法)标记了@Autowired,那么会自动在容器中查找该属性类型的对象,如果有且只有一个,则注入。

注意:如果有两个userDao的实现类,则会报错。
解决方法:
一、在@Autowired下配置上需要注入的名称,使用注解@Qualifier

@Qualifier("userDaoImpl2")
@Service("userService")
public class UserServiceImpl implements UserService {
    @Autowired
    @Qualifier("userDaoImpl2")
    UserDao userDao;

    public void print(){
        userDao.print();
    }
}

二、根据属性名注入

@Service("userService")
public class UserServiceImpl implements UserService {
    @Autowired
    UserDao userDaoImpl2;

    public void print(){
        userDaoImpl2.print();
    }
}

自动注入@Resource

如果没有@Resource注解,则写入依赖

<dependency>
            <groupId>javax.annotation</groupId>
            <artifactId>javax.annotation-api</artifactId>
            <version>1.3.1</version>
        </dependency>

流程:当属性或方法(set方法)标记了@Resource

  • 按照名称查找:会自动按照名称注入,如果指定了名称,则按照名称注入;如果没有指定名字,则按照属性名注入。
  • 按照类型查找:如果名称没有找到,则按照类型注入;类型有多个则抛出异常

按照指定的名称注入

@Service("userService")
public class UserServiceImpl implements UserService {
    @Resource(name="userDaoImpl2")
    UserDao userDao;

    public void print(){
        userDao.print();
    }
}

按照属性名注入

@Service("userService")
public class UserServiceImpl implements UserService {
    @Resource
    UserDao userDaoImpl2;

    public void print(){
        userDaoImpl2.print();
    }
}

按照类型注入(属性名找不到对应的类时):如果有多个则报异常

@Service("userService")
public class UserServiceImpl implements UserService {
    @Resource
    UserDao userDao;

    public void print(){
        userDao.print();
    }
}

@Autowired@Resource区别
@Autowired

  • 默认按照类型注入,如果类型有多个,则按照名称注入
  • spring提供

@Resource

  • 默认按照名称注入,如果名称没有找到,则按照类型注入
  • jdk提供

使用半注解半xml改造账户CRUD

开启注解中有两个属性
1、context:include-filter:指定包含过滤

  • type="annotation"按照类型过滤
  • expression=""过滤的表达式

在下边代码中的含义:只扫描标记了Controller注解的类

2、context:exclude-filter:指定排除过滤

  • type="annotation"按照类型过滤
  • expression=""过滤的表达式

在下边代码中的含义:除了Controller注解都会扫描

<!--开启注解,扫描包-->
    <context:component-scan base-package="com.itheima">
        <!--
            context:include-filter:指定包含过滤
                type="annotation"按照类型过滤
                expression=""过滤的表达式

                只扫描标记了Controller注解的类
        -->
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
        <!--
            context:exclude-filter:指定排除过滤
                type="annotation"按照类型过滤
                expression=""过滤的表达式

                除了Controller注解都会扫描
        -->
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>

配置文件

<?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">

    <!--开启注解,扫描包-->
    <context:component-scan base-package="com.itheima"></context:component-scan>

    <!--创建qr对象,需要数据源对象,通过构造方法的参数类型注入-->
    <bean id="qr" class="org.apache.commons.dbutils.QueryRunner">
        <constructor-arg type="javax.sql.DataSource" ref="dataSource"></constructor-arg>
    </bean>
    <!--创建数据源对象:需要注入四个参数,通过set方法注入-->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/spring"></property>
        <property name="user" value="root"></property>
        <property name="password" value="root"></property>
    </bean>
</beans>

AccountDaoImpl

@Repository("accountDao")
public class AccountDaoImpl implements AccountDao {
    @Autowired
    QueryRunner qr;
    //...省略
}

AccountServiceImpl

import com.itheima.dao.AccountDao;
import com.itheima.dao.impl.AccountDaoImpl;
import com.itheima.domain.Account;
import com.itheima.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service("accountService")
public class AccountServiceImpl implements AccountService {
    //创建容器,使用依赖注入
    @Autowired
    private AccountDao accountDao;
    //...省略
}

测试类

@Test
    public void test(){
        //创建容器
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
        //创建service对象
        AccountService accountService = ac.getBean("accountService",AccountService.class);
        List<Account> accountList = accountService.findAll();
        for (Account account : accountList) {
            System.out.println(account);
        }
    }

纯注解开发案例

使用纯注解改造账户CRUD

一、创建SpringConfiguration.java

  1. 标记该类为配置文件类 @Configuration
  2. 指定注解扫描的包路径 @ComponentScan({"com.itheima"})
  3. 引入其他配置文件类 @Import({JDBCConfiguration.class})
package com.itheima.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

/**
 * 1、标记该类为配置文件类    @Configuration
 * 2、指定注解扫描的包路径    @ComponentScan({"com.itheima"})
 * 3、引入其他配置文件类      @Import({JDBCConfiguration.class})
 *
 *
 */
@Configuration
@ComponentScan({"com.itheima"})
@Import({JDBCConfiguration.class})
public class SpringConfiguration {
}

二、创建JDBCConfiguration.java

  • @Configuration:可以省略
  • @Bean("name")用在方法上,用来指定方法创建的对象存到容器中,一般用于别人的类,相当于<bean>标签
    "name"就是在容器中的名称
package com.itheima.config;

import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.apache.commons.dbutils.QueryRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;
import java.beans.PropertyVetoException;

/**
 * 配置持久层的对象
 * @Configuration:可以省略
 * @Bean("name"):用在方法上,用来指定方法创建的对象存到容器中
 *          "name"就是在容器中的名称
 *
 */
@Configuration
public class JDBCConfiguration {
    @Bean("queryRunner")
    public QueryRunner createQueryRunner(DataSource dataSource){
        //需要通过构造方法,注入dataSource
        QueryRunner queryRunner = new QueryRunner(dataSource);
        return queryRunner;
    }
    /**
     * 创建数据源对象:dataSource
     * @return
     */
    @Bean("dataSource")
    public DataSource createDataSource(){
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/spring");
        dataSource.setUser("root");
        dataSource.setPassword("root");
        try {
            dataSource.setDriverClass("com.mysql.jdbc.Driver");
        } catch (PropertyVetoException e) {
            e.printStackTrace();
        }
        return dataSource;
    }
}

三、测试
注意:使用ApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfiguration.class);

 @Test
    public void test(){
        //创建容器
//        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
        //纯注解创建容器对象
        ApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfiguration.class);

        //创建service对象
        AccountService accountService = ac.getBean("accountService",AccountService.class);
        List<Account> accountList = accountService.findAll();
        for (Account account : accountList) {
            System.out.println(account);
        }
    }

改造纯注解

改造一:数据库的一些属性写死了,把他们放到配置文件中

  • @PropertySource({"jdbc.properties"})引入properties文件
  • @Value给属性赋值
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/spring
jdbc.username=root
jdbc.password=root
package com.itheima.config;

import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.apache.commons.dbutils.QueryRunner;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;

import javax.sql.DataSource;
import java.beans.PropertyVetoException;

/**
 * 配置持久层的对象
 * @Configuration:可以省略
 * @Bean("name"):用在方法上,用来指定方法创建的对象存到容器中
 *          "name"就是在容器中的名称
 *
 */
@Configuration
@PropertySource({"jdbc.properties"})
public class JDBCConfiguration {
    @Value("${jdbc.url}")
    private String url;
    @Value("${jdbc.driver}")
    private String driverClass;
    @Value("${jdbc.username}")
    private String username;
    @Value("${jdbc.password}")
    private String password;

    @Bean("queryRunner")
    public QueryRunner createQueryRunner(DataSource dataSource){
        //需要通过构造方法,注入dataSource
        QueryRunner queryRunner = new QueryRunner(dataSource);
        return queryRunner;
    }
    /**
     * 创建数据源对象:dataSource
     * @return
     */
    @Bean("dataSource")
    public DataSource createDataSource(){
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        dataSource.setJdbcUrl(url);
        dataSource.setUser(username);
        dataSource.setPassword(password);
        try {
            dataSource.setDriverClass(driverClass);
        } catch (PropertyVetoException e) {
            e.printStackTrace();
        }
        return dataSource;
    }
}

改造二:创建的对象默认是单例模式,将他改成多例模式

在类上添加注解@Scope("prototype")

@Repository("accountDao")
@Scope("prototype")
public class AccountDaoImpl implements AccountDao 

改造三:可以添加对象的初始化和销毁方法(一般不用)

  • @PostConstruct:相当于bean标签的属性init-method,指定初始化方法
  • @PreDestroy:相当于bean标签的属性:destroy-method,指定对象的销毁方法

xml引入外部文件

一、xml中引入xml

关键代码

<import resource="classpath:applicationContext-dao.xml"></import>

applicationContext.xml

<?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">
    <!--引入外部属性文件-->
    <import resource="classpath:applicationContext-dao.xml"></import>
    <!--创建AccountService对象:需要AccountDao对象,依赖注入dao对象-->
    <bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
        <property name="accountDao" ref="accountDao"></property>
    </bean>

</beans>

applicationContext-dao.xml

<?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">
    <!--创建AccountDao对象,需要qr-->
    <bean id="accountDao" class="com.itheima.dao.impl.AccountDaoImpl">
        <!--通过set方法注入qr-->
        <property name="qr" ref="qr"></property>
    </bean>
    <!--创建qr对象,需要数据源对象,通过构造方法的参数类型注入-->
    <bean id="qr" class="org.apache.commons.dbutils.QueryRunner">
        <constructor-arg type="javax.sql.DataSource" ref="dataSource"></constructor-arg>
    </bean>
    <!--创建数据源对象:需要注入四个参数,通过set方法注入-->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/spring"></property>
        <property name="user" value="root"></property>
        <property name="password" value="root"></property>
    </bean>
</beans>

二、xml中引入properties文件

关键代码

<context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>

applicationContext-dap.xml

<?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">
    <!--创建AccountDao对象,需要qr-->
    <bean id="accountDao" class="com.itheima.dao.impl.AccountDaoImpl">
        <!--通过set方法注入qr-->
        <property name="qr" ref="qr"></property>
    </bean>
    <!--创建qr对象,需要数据源对象,通过构造方法的参数类型注入-->
    <bean id="qr" class="org.apache.commons.dbutils.QueryRunner">
        <constructor-arg type="javax.sql.DataSource" ref="dataSource"></constructor-arg>
    </bean>
    <!--创建数据源对象:需要注入四个参数,通过set方法注入-->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="${jdbc.driver}"></property>
        <property name="jdbcUrl" value="${jdbc.url}"></property>
        <property name="user" value="${jdbc.username}"></property>
        <property name="password" value="${jdbc.password}"></property>
    </bean>

    <!--引入外部属性文件-->
    <context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
</beans>

jdbc.properties

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/spring
jdbc.username=root
jdbc.password=root
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章