【Spring实战】1.1 简化 Java 开发

依赖注入

什么是依赖注入

在构造函数中自行创建依赖的对象,高度耦合:

public DamselRescuingKnight() {
    this.quest = new RescueDamselQuest();
}

将对象的依赖关系交给第三方组件管理,无需自行创建,这是依赖注入:

public BraveKnight(Quest quest) {
    this.quest = quest;
}

Spring 怎么实现装配

怎么把 Quest 交给 Knight 呢?

XML 的装配方式:

<!-- 在pom.xml加上Spring的依赖,右键新建XML就可以看到Spring Config了 -->
<bean id="knight" class="sia.knights.BraveKnight">
    <constructor-arg ref="quest"/>
</bean>

<bean id="quest" class="sia.knights.SlayDragonQuest">
    <constructor-arg value="#{T(System).out}"/>
</bean>

Java 的装配方式:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class KnightConfig {
    @Bean
    public Knight knight() {
        return new BraveKnight(quest());
    }
    @Bean
    public Quest quest() {
        return new SlayDragonQuest(System.out);
    }
}

获取 Spring 装配好的 Bean

加载 Spring 的上下文

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>4.0.7.RELEASE</version>
</dependency>
public static void main(String[] args) {
    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("knights.xml");
    Knight knight = context.getBean(Knight.class);
    knight.embarkOnQuest();
    context.close();
}

阅读 spring core与context理解 后,我的理解是 Spring Core 拥有 BeanFactory,Spring Context 基于 Spring Core,它们是 IOC 容器。

AOP 切面编程

如果没有切面编程

public void embarkOnQuest() {
  minstrel.singBeforeQuest();
  quest.embark();
  minstrel.singAfterQuest();
}

但骑士真的要管理吟游诗人吗?应交由 Spring 配置管理:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aop</artifactId>
    <version>4.0.7.RELEASE</version>
</dependency>
<!-- Spring AOP 依赖 AspectJ,不然会报 ReflectionWorldException-->
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.7.2</version>
    <scope>runtime</scope>
</dependency>
<aop:config>
    <aop:aspect ref="minstrel">
        <!-- execution(修饰符 返回值 包名.类名/接口名.方法名(参数列表)) -->
        <aop:pointcut id="embark" expression="execution(* *.embarkOnQuest(..))"/>
        <aop:before pointcut-ref="embark" method="singBeforeQuest"/>
        <aop:after pointcut-ref="embark" method="singAfterQuest"/>
    </aop:aspect>
</aop:config>

模板

原始的 JDBC 连接

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.38</version>
</dependency>

<!-- 在 Maven 仓库查询后,往下拉,可以看对应 mysql 的版本 -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.0.22</version>
</dependency>
public Employee getEmployeeById(Long id) throws Exception {
    /*
    获取连接
    方式一:注册驱动
    Class.forName("com.mysql.jdbc.Driver");
    Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "root");
    方式二:连接池
    //数据源配置
    DruidDataSource dataSource = new DruidDataSource();
    dataSource.setUrl("jdbc:mysql://127.0.0.1/db_student?serverTimezone=UTC");
    dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver"); //这个可以缺省的,会根据url自动识别
    dataSource.setUsername("root");
    dataSource.setPassword("abcd");
     */

    Properties properties = new Properties();
    InputStream is = EmployeeTest.class.getResourceAsStream("/druid.properties");
    properties.load(is);
    //返回的是DataSource,不是DruidDataSource
    DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);

    try (Connection conn = dataSource.getConnection();
         PreparedStatement stmt = createPreparedStatement(conn, id);
         ResultSet rs = stmt.executeQuery()) {
        Employee employee = null;
        if (rs.next()) {
            employee = new Employee();
            employee.setId(rs.getLong("id"));
            employee.setName(rs.getString("name"));
        }

        return employee;
    }
}

private PreparedStatement createPreparedStatement(Connection conn, Long id) throws SQLException {
    String sql = "SELECT id, name FROM employee where id=?";
    PreparedStatement ps = conn.prepareStatement(sql);
    ps.setLong(1, id);
    return ps;
}
url=jdbc:mysql://localhost:3306/test?useSSL=false
# 这个可以缺省的,会根据url自动识别
driverClassName=com.mysql.jdbc.Driver
username=root
password=root
# 初始连接数,默认0
initialSize=10
# 最大连接数,默认8
maxActive=30
# 最小闲置数
minIdle=10
# 获取连接的最大等待时间,单位毫秒
maxWait=2000
# 缓存PreparedStatement,默认false
poolPreparedStatements=true
# 缓存PreparedStatement的最大数量,默认-1(不缓存)。大于0时会自动开启缓存PreparedStatement,所以可以省略上一句设置
maxOpenPreparedStatements=20

使用 JdbcTemplate 模板

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>4.0.7.RELEASE</version>
</dependency>
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import java.sql.ResultSet;
import java.sql.SQLException;
public class JdbcDemo {
    private JdbcTemplate jdbcTemplate;
    public JdbcDemo(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }
    public Employee getEmployeeById(Long id) {
        return jdbcTemplate.queryForObject("SELECT id, name FROM employee where id=?",
                // 将结果匹配为对象
                new RowMapper<Employee>() {
                    @Override
                    public Employee mapRow(ResultSet rs, int rowNum) throws SQLException {
                        Employee employee = new Employee();
                        employee.setId(rs.getLong("id"));
                        employee.setName(rs.getString("name"));
                        return employee;
                    }
                }, 1L
        );
    }
}
<bean id="dataSource"
      class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <!-- 配置数据源 -->
    <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
    <property name="url" value="jdbc:mysql://localhost:3306/test?useSSL=false"></property>
    <property name="username" value="root"></property>
    <property name="password" value="root"></property>
</bean>
<!-- 配置JDBC模板 -->
<bean id="jdbcTemplate"
      class="org.springframework.jdbc.core.JdbcTemplate">
    <!-- 默认必须使用数据源 -->
    <property name="dataSource" ref="dataSource"></property>
</bean>
<bean id="jdbcDemo" class="sia.knights.JdbcDemo">
    <constructor-arg ref="jdbcTemplate"/>
</bean>
posted @ 2023-05-10 11:36  seolas  阅读(11)  评论(0编辑  收藏  举报