Spring

Spring

一、概述:

以下概述内容拷自w3cschool

Spring 是最受欢迎的企业级 Java 应用程序开发框架,数以百万的来自世界各地的开发人员使用 Spring 框架来创建性能好、易于测试、可重用的代码。
Spring 框架是一个开源的 Java 平台,它最初是由 Rod Johnson 编写的,并且于 2003 年 6 月首次在 Apache 2.0 许可下发布。
Spring 是轻量级的框架,其基础版本只有 2 MB 左右的大小。
Spring 框架的核心特性是可以用于开发任何 Java 应用程序,但是在 Java EE 平台上构建 web 应用程序是需要扩展的。
Spring 框架的目标是使 J2EE 开发变得更容易使用,通过启用基于 POJO 编程模型来促进良好的编程实践。

两大重点:

1.依赖注入(DI)
Spring 最认同的技术是控制反转的依赖注入(DI)模式。控制反转(IoC)是一个通用的概念,它可以用许多不同的方式去表达,依赖注入仅仅是控制反转的一个具体的例子。

当编写一个复杂的 Java 应用程序时,应用程序类应该尽可能的独立于其他的 Java 类来增加这些类可重用可能性,当进行单元测试时,可以使它们独立于其他类进行测试。依赖注入(或者有时被称为配线)有助于将这些类粘合在一起,并且在同一时间让它们保持独立。

到底什么是依赖注入?让我们将这两个词分开来看一看。这里将依赖关系部分转化为两个类之间的关联。例如,类 A 依赖于类 B。现在,让我们看一看第二部分,注入。所有这一切都意味着类 B 将通过 IoC 被注入到类 A 中。

依赖注入可以以向构造函数传递参数的方式发生,或者通过使用 setter 方法 post-construction。由于依赖注入是 Spring 框架的核心部分,所以我将在一个单独的章节中利用很好的例子去解释这一概念。

2.面向方面的程序设计(AOP):
Spring 框架的一个关键组件是面向方面的程序设计(AOP)框架。一个程序中跨越多个点的功能被称为横切关注点,这些横切关注点在概念上独立于应用程序的业务逻辑。有各种各样常见的很好的关于方面的例子,比如日志记录、声明性事务、安全性,和缓存等等。

在 OOP 中模块化的关键单元是类,而在 AOP 中模块化的关键单元是方面。AOP 帮助你将横切关注点从它们所影响的对象中分离出来,然而依赖注入帮助你将你的应用程序对象从彼此中分离出来。

Spring 框架的 AOP 模块提供了面向方面的程序设计实现,可以定义诸如方法拦截器和切入点等,从而使实现功能的代码彻底的解耦出来。使用源码级的元数据,可以用类似于.Net属性的方式合并行为信息到代码中。

二、Ioc:

2.1spring Ioc容器(控制反转):

作用:减小类/程序间的耦合

个人理解:运行时,找对象的事变成了间接寻找。没有使用ioc时,是直接寻找,找不到,编译便报错,而使用后,spring会创建一个工厂,寻找的事交给了工厂来处理,由工厂来寻找所需要的类,这样便减少了类与类之间的耦合,进一步实现低耦合高内聚!但Ioc只能做到减小,无法做到真正的解耦。

2.2 两大容器:

2.2.1:BeanFactory 容器和 ApplicationContext 容器(常用):

BeanFactory 可以理解为含有bean集合的工厂类。而 ApplicationContext 是他的一个子接口(进行了扩展)。

BeanFactory 是一个基本的容器,他无法支持aop、web等功能。

BeanFactory 能做到的事, ApplicationContext 都能做到。

ApplicationContext: 单例对象适用 采用此接口

它在构建核心容器时,创建对象采取的策略是采用立即加载的方式。也就是说,只要一读取完配置文件马上就创建配置文件中配置的对象。

BeanFactory: 多例对象使用

它在构建核心容器时,创建对象采取的策略是采用延迟加载的方式。也就是说,什么时候根据id获取对象了,什么时候才真正的创建对象。

2.2.2 ApplicationContext的三个常用实现类:

 ClassPathXmlApplicationContext:它可以加载类路径下的配置文件,要求配置文件必须在类路径下。不在的话,加载不了。(更常用)

 FileSystemXmlApplicationContext:它可以加载磁盘任意路径下的配置文件(必须有访问权限)

 AnnotationConfigApplicationContext: 读取注解创建容器

相关代码:
    ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
    xxx x = (xxx)ac.getBean("xxx"); //要强转类型
    xxx x = ac.getBean("xxx",xxx.class);

bean.xml


    

        
        
    

2.3 spring对bean的管理细节

2.3.1 创建bean的三种方式

1.使用默认构造函数创建,在spring配置文件配id和class属性的bean


2.使用普通工厂中的方法创建对象(使用某个类中的方法创建对象,并存入spring容器)



3.使用工厂中的静态方法创建对象(使用某个类中的静态方法创建对象,并存入spring容器)

2.3.2 bean对象的作用范围

scope属性: 
    *singleton  单例(默认)
    *prototype  多例
    *request    web应用的请求范围
    *session    web应用的会话范围
    *global-session:    作用于集群环境的会话范围

2.3.3 bean对象的生命周期

单例对象

出生:容器创建时

活着:容器在便在

死亡:容器销毁,死亡

多例对象

出生:当我们使用spring框架为我们创建(同beanFactory)

活着:对象在使用,就活着

死亡:等着java垃圾回收机制回收

2.4 依赖注入(DI)

1.能注入的数据:
    1.基本类型和String
    2.其他bean类型
    3.复杂类型/集合类型
        
2.注入方式:
    1.使用构造函数注入
        使用的标签:constructor-arg
        标签内的属性:
            type:指定注入的数据的数据类型,也是构造函数中某个或某些参数的类型
            index:用于指定注入的数据给构造函数中指定索引位置赋值
            name:用于指定给构造函数中指定名称的参数赋值
            value:提供基本类型和String类型的数据
            ref:指定其他的bean类型数据,即在Ioc核心容器中出现过的bean对象
    
        
    
        
    2.使用set注入(常用)
        标签:property
        标签内属性:
            name:注入时所调用的set方法名称
            ref:指定其他的bean类型数据,即在Ioc核心容器中出现过的bean对象
        
    使用注解注入

2.5注解:

在bean.xml中要先表明扫描的包(要加新的约束)

创建对象:

    Component:将当前类对象存入spring容器,有个value属性:相当于bean的id(默认为当前类名第一个字母小写)
    以下三个与上面作用一模一样
        Controller:一般用于表现层
        Service:一般用于业务层
        Repository:一般用于持久层
        

注入数据:

    作用同bean标签的
    1.Autowired:按照类型自动注入,此时set方法不为必须的了
        注入时,没有匹配类型则报错,如果多个匹配的类型,则以id来匹配
    2.Qualifier:按照类中注入的基础之上再按照名称注入,注入类成员不能单独食用,给    方法参数可以,属性value:用于指定注入bean的id。
    3.Resource:直接按照bean的id注入
    以上3个只能注入其他bean类型,基本类型和String不能,另外,集合类型只能通过xml实现
        
    4.Value:用于注入基本类型和String

指定作用范围:

    Scope:
        *singleton  单例
        *prototype  多例

配置类注解:

作用同bean.xml
    1.Congifuration:表面当前类是一个配置类
    2.ComponentScan:通过注解表面spring创建容器时要扫描的包
    3.Bean:用于把当前方法的返回值作为bean对象存入springIoc容器,属性name:指定bean的id,默认方法名称
    4.Import():  用于插入其他配置类
    5.PropertySource: 扫描的配置文件(一般是jdbc.properties)
    6.@EnableTransactionManagement:开启事务支持

2.6案例:

xml配置案例:

bean.xml:



    
        
    

    
        
    

    
        
    

    
            
            
            
            
    

AccountServiceImpl:

public class AccountServiceImpl implements AccountService {
    private AccountDao accountDao;

    public void setAccountDao(AccountDao accountDao) {
        this.accountDao = accountDao;
    }

    public List findAllAccount() {
        return accountDao.findAllAccount();
    }

    public Account findAccountById(Integer accountId) {
        return accountDao.findAccountById(accountId);
    }

    public void saveAccount(Account account) {
        accountDao.saveAccount(account);
    }

    public void updateAccount(Account account) {
        accountDao.updateAccount(account);
    }

    public void deleteAccount(Integer accountId) {
        accountDao.deleteAccount(accountId);
    }
}

AccountService:

public interface AccountService {

    /*
    查询所有
     */
    List findAllAccount();

    /*
    根据id查找
     */
    Account findAccountById(Integer accountId);

    /*
    保存
     */
    void saveAccount(Account account);

    /*
    更新
     */
    void updateAccount(Account account);

    /*
    删除
     */
    void deleteAccount(Integer accountId);
}

AccountDao:

public interface AccountDao {
    /*
    查询所有
     */
    List findAllAccount();

    /*
    根据id查找
     */
    Account findAccountById(Integer accountId);

    /*
    保存
     */
    void saveAccount(Account account);

    /*
    更新
     */
    void updateAccount(Account account);

    /*
    删除
     */
    void deleteAccount(Integer accountId);
}

AccountDaoImpl:

public class AccountDaoImpl implements AccountDao {
    private QueryRunner runner;

    public void setRunner(QueryRunner runner) {
        this.runner = runner;
    }

    public List findAllAccount() {
        try {
            return runner.query("select *from account",new BeanListHandler(Account.class));
        }catch (Exception e){
            throw new RuntimeException(e);
        }
    }

    public Account findAccountById(Integer accountId) {
        try {
            return runner.query("select *from account where id = ?",new BeanHandler(Account.class),accountId);
        }catch (Exception e){
            throw new RuntimeException(e);
        }
    }

    public void saveAccount(Account account) {
        try {
             runner.update("insert into account(name,money) value (?,?)",
                     account.getName(),account.getMoney());
        }catch (Exception e){
            throw new RuntimeException(e);
        }
    }

    public void updateAccount(Account account) {
        try {
            runner.update("update  account set name=?,money=? where id=?",
                   account.getName(),account.getMoney(),account.getId());
        }catch (Exception e){
            throw new RuntimeException(e);
        }
    }

    public void deleteAccount(Integer accountId) {
        try {
            runner.update("delete from  account where id = ?",
                 accountId);
        }catch (Exception e){
            throw new RuntimeException(e);
        }
    }
}

Test:

public class TestCurd {
    @Test
    public void TestFindAll() {
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        AccountService as = ac.getBean("accountService",AccountService.class);
        List accounts = as.findAllAccount();
        for (Account account : accounts) {
            System.out.println(account);
        }
    }

    @Test
    public void TestFindOne() {
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        AccountService as = ac.getBean("accountService",AccountService.class);
        Account account = as.findAccountById(1);
        System.out.println(account);
    }

    @Test
    public void TestSaveAccount() {
        Account account = new Account();

        account.setName("老王");
        account.setMoney(1234f);

        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        AccountService as = ac.getBean("accountService",AccountService.class);

        as.saveAccount(account);
    }

    @Test
    public void TestUpdateAccount() {
        Account account = new Account();
        account.setId(1);
        account.setName("AAA");
        account.setMoney(1234f);
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        AccountService as = ac.getBean("accountService",AccountService.class);
        as.updateAccount(account);
    }

    @Test
    public void TestDeleteAccount() {
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        AccountService as = ac.getBean("accountService",AccountService.class);

        as.deleteAccount(4);
    }
}

注解配置:

SpringConfiguration:

/**
 * 相当于bean.xml
 */

@Configuration     //表明他是一个配置类,会被被AnnotationConfigApplicationContext或AnnotationConfigWebApplicationContext类进行扫描,并用于构建bean定义,初始化Spring容器。
@ComponentScan("cn.zzz")  //表面创建容器扫描的包
public class SpringConfiguration {

    @Bean("runner")
    @Scope("prototype")
    public QueryRunner runner(DataSource dataSource) {
        return new QueryRunner(dataSource);
    }

    @Bean("dataSource")
    public DataSource creatDatasource() {
        ComboPooledDataSource cbp = new ComboPooledDataSource();
        try {
            cbp.setDriverClass("com.mysql.cj.jdbc.Driver");
            cbp.setJdbcUrl("jdbc:mysql://localhost:3306/spring01?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC");
            cbp.setUser("root");
            cbp.setPassword("lin990306");
            return cbp;
        } catch (Exception e) {
           throw new RuntimeException(e);
        }
    }
}

AccountServiceImpl:

@Service("accountService")
public class AccountServiceImpl implements AccountService {
    
    @Autowired
    private AccountDao accountDao;


    public List findAllAccount() {
        return accountDao.findAllAccount();
    }

    public Account findAccountById(Integer accountId) {
        return accountDao.findAccountById(accountId);
    }

    public void saveAccount(Account account) {
        accountDao.saveAccount(account);
    }

    public void updateAccount(Account account) {
        accountDao.updateAccount(account);
    }

    public void deleteAccount(Integer accountId) {
        accountDao.deleteAccount(accountId);
    }
}

AccountDaoImpl:

@Repository("accountDao")
public class AccountDaoImpl implements AccountDao {


    @Autowired
    private QueryRunner runner;



    public List findAllAccount() {
        try {
            return runner.query("select *from account",new BeanListHandler(Account.class));
        }catch (Exception e){
            throw new RuntimeException(e);
        }
    }

    public Account findAccountById(Integer accountId) {
        try {
            return runner.query("select *from account where id = ?",new BeanHandler(Account.class),accountId);
        }catch (Exception e){
            throw new RuntimeException(e);
        }
    }

    public void saveAccount(Account account) {
        try {
             runner.update("insert into account(name,money) value (?,?)",
                     account.getName(),account.getMoney());
        }catch (Exception e){
            throw new RuntimeException(e);
        }
    }

    public void updateAccount(Account account) {
        try {
            runner.update("update  account set name=?,money=? where id=?",
                   account.getName(),account.getMoney(),account.getId());
        }catch (Exception e){
            throw new RuntimeException(e);
        }
    }

    public void deleteAccount(Integer accountId) {
        try {
            runner.update("delete from  account where id = ?",
                 accountId);
        }catch (Exception e){
            throw new RuntimeException(e);
        }
    }
}

其他与xml配置案例一样

三、Aop

AOP是Spring框架面向切面的编程思想,AOP采用一种称为“横切”的技术,将涉及多业务流程的通用功能抽取并单独封装,形成独立的切面,在合适的时机将这些切面横向切入到业务流程指定的位置中。

相关术语:

Joinpoint(连接点): 所谓连接点是指那些被拦截到的点。在 spring 中,这些点指的是方法,因为 spring 只支持方法类型的 连接点。

Pointcut(切入点): 所谓切入点是指我们要对哪些 Joinpoint 进行拦截的定义。

Advice(通知/增强): 所谓通知是指拦截到 Joinpoint 之后所要做的事情就是通知。 通知的类型:前置通知,后置通知,异常通知,最终通知,环绕通知。

Introduction(引介): 引介是一种特殊的通知在不修改类代码的前提下, Introduction 可以在运行期为类动态地添加一些方 法或 Field。

Target(目标对象): 代理的目标对象。

Weaving(织入): 是指把增强应用到目标对象来创建新的代理对象的过程。 spring 采用动态代理织入,而 AspectJ 采用编译期织入和类装载期织入。

Proxy(代理): 一个类被 AOP 织入增强后,就产生一个结果代理类。

Aspect(切面): 是切入点和通知(引介)的结合

xml约束:







        org.aspectj
        aspectjweaver
        1.8.7
    

四:spring中的事务管理

题外:使用jdbcTemplate时,可以在dao中继承JdbcDaoSupport,便可以省去定义和注入,使用时直接super.getJdbcTemplate().方法。

基于xml的事务管理:
bean.xml:



    
        
    

    
        
    



    
        
        
        
        
    


    

    
    
        
    
    
    
        
        
            
            
        
    

    
    
    
        
        
        
    

AccountServiceImpl:
public class AccountServiceImpl implements AccountService {

    private AccoundDao accountDao;

    public void setAccountDao(AccoundDao accoundDao) {
        this.accountDao = accoundDao;
    }

    public Account findAccoundByName(String AccountName) {
        return accountDao.findAccoundByName(AccountName);
    }

    public void updateAccount(Account account) {
        accountDao.updateAccount(account);
    }

    public List findAll() {
        return accountDao.findAll();
    }

    public void transfer(String outName, String inName, Float money) {
        Account outAccount = accountDao.findAccoundByName(outName);
        Account inAccount = accountDao.findAccoundByName(inName);

        outAccount.setMoney(outAccount.getMoney()-money);
        inAccount.setMoney(inAccount.getMoney()+money);

        accountDao.updateAccount(outAccount);

//        int i =1/0;
        accountDao.updateAccount(inAccount);
    }
}
Test:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:bean.xml")
public class AccountServiceTest {

    @Autowired
    private AccountService as;

    @Test
    public void TestFindAll(){
        List accounts = as.findAll();
        for (Account account : accounts) {
            System.out.println(account);
        }
    }

    @Test
    public void TestFindAccountByName(){

        Account account = as.findAccoundByName("AAA");
        System.out.println(account);
    }

    @Test
    public void TestTransfer(){

        as.transfer("AAA","bbb",100f);
    }
}

这种单元测试写法是为了让测试在Spring容器环境下执行。

你可能感兴趣的:(Spring)