欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Spring入门学习笔记

程序员文章站 2024-03-23 08:09:10
...

Spring学习笔记

尊重原创,转载请注明出处,原文地址: http://blog.csdn.net/qq137722697


如图片加载不出来,请看:https://github.com/huangdali/spring

什么是Spring

1、Spring是一个开源的轻量级框架

2、Spring核心:

  • ioc:控制反转

    • 比如有一个类,在类里面有一个方法(非静态方法),在使用这个类的方法的时候需要通过 new 对象名() 来实现
    • ioc就是将new对象的过程交给了Spring来做
  • aop:面向切面编程

    • 简单来说就是:扩展功能时不需要修改原代码来实现

3、Spring是一站式框架

Spring在javaee三层结构中,每一层都提供了不同的解决技术

  • web层:Spring MVC

  • service层:Sping的ioc

  • dao层:Spring的jdbcTemplate

4、Spring的版本

目前使用Spring 4.X版本来开发

IOC学习

IOC底层实现原理

1、xml配置

2、dom4j解析xml

3、工厂模式

4、反射

图解:

Spring入门学习笔记

Bean标签常用属性

  • id属性:bean使用的名称
    • 不能包含特殊符号
    • 根据id值拿到class配置对象
  • class属性:需要注入对象的全路径
  • name属性:功能和id属性一样
    • 可以包含一些特殊符号(基本不用)
  • scope属性:作用范围(作用域)
    • singleton :默认值,单例
    • prototype :多例
    • request :web项目中,Spring创建一个bean的对象,将对象存入到request域中
    • session :web项目中,Spring创建一个Bean的对象,将对象存入到session域中
    • globalSeesion :web项目中,应用在porlet环境,如果没有porlet,那么globalsession相当于session

属性注入

使用bean创建对象的时候,向类里面注入属性

属性注入的三种方式:

1、set方法注入(最常用)

1.1、入门:
    <!--属性注入->属性注入-->
    <bean id="property2" class="com.hdl.ioc.PropertyDi">
        <!--name表示类中的属性值-->
        <property name="username" value="hah"/>
    </bean>
  @Test
    public void testProperty2() {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        PropertyDi propertyDi = (PropertyDi) context.getBean("property2");
        propertyDi.print();
    }
1.2、常用

实际开发中:

/**
* 实际数据库操作的地方
*/
public class UserDao {
    public boolean add(String context){
        System.out.println("insert--------"+context);
        return true;
    }
}

//供接口调用的服务类

public class UserService {
    private UserDao userDao;//dao通过set注入,不在需要new对象

    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    public boolean add(String context) {
        //常规方法--->bean的话不用new了
//        UserDao userDao=new UserDao();
        return userDao.add(context);
    }
}

配置

    <!--属性注入->set属性注入->set对象-->
    <bean id="userDaoConfig" class="com.hdl.ioc.UserDao"/>
    <bean id="userService" class="com.hdl.ioc.UserService">
        <property name="userDao" ref="userDaoConfig">
        </property>
    </bean>

使用/servlet调用

    @Test
    public void testProperty3() {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserService userService = (UserService) context.getBean("userService");
        System.out.println("执行service的结果: " + userService.add("我去,整个过程就不需要new UserDao()了"));
    }

输出

add--------我去,整个过程就不需要new UserDao()了
执行service的结果: true
1.3、名字空间注入(不常用)

Spring入门学习笔记

1.4、复杂类型注入(不常用)
  • 数组

Spring入门学习笔记

  • list集合

Spring入门学习笔记

  • map集合、properties

Spring入门学习笔记

2、构造方法注入

配置:

 <bean id="property1" class="com.hdl.ioc.PropertyDi">
        <constructor-arg name="username" value="大力哥">
        </constructor-arg>
    </bean>

使用:

    @Test
    public void testProperty1() {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        PropertyConstructer propertyDi = (PropertyConstructer) context.getBean("property1");
        propertyDi.print();
    }

3、接口注入(Bean 不支持这种注入)

public interface Dao{
    void delte(String name);
}

public class DaoImpl implements Dao{
    private String name;
    public void delete(String name){
        this.name=name;
    }
}

ioc与di的区别

  • ioc :控制反转,把对象创建交给Spring来配置bean;
  • di :依赖注入,向类里面注入属性;
  • 关系 :di需要不能单独存在,需要在ioc的基础上完成

Spring整合web开发

1、action中加载配置文件

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

问题:new 对象,功能可以实现,效率却很低

2、优化思想:把配置加载文件和创建对象的过程,在服务器启动的时候完成

3、实现原理:

3.1、ServletContext对象(存域中)

3.2、监听器(ServletContextListener)

3.3、具体使用:

  • 在服务器启动的时候,为每个项目创建servletcontext对象

  • 在servletcontext对象创建的时候,使用监听器可以监听servletcontext的生命周期

  • 在监听到创建serveltcontext对象的时候,加载Spring配置文件,根据配置文件创建对象

  • 把创建出来的对象存到servletcontext域对象里面(调用setAttribute方法)

  • 获取对象的时候,到servletcontext域对象里面取即可(调用getAttribute方法)

注解

代码里面标记,使用注解来完成功能 如@Test

1、使用范围:可以使用在类、方法、属性上面

2、达到的效果:可以替代大部分配置文件

Spring注解开发准备

主要导入aop包

创建配置文件并配置开启注解扫描

 <!--开启注解扫描
    会根据base-package填写的包名,扫描所有的属性、方法、类上是否有注解
    -->
    <context:component-scan base-package="com.hdl.ioc.day02.bean"/>
    <!--用下面这个配置,只会扫描属性上面的注解-->
    <!--<context:annotation-config></context:annotation-config>-->

1、注解创建对象

第一步:在需要对象注入的对象中使用Component注解

@Scope(value = "prototype")//不配置的话默认singleton
@Component(value = "user")//相当于配置<bean id="user">
public class User {
    public void add() {
        System.out.println("add............");
    }
}

第二步:测试

 @Test
    public void testUser(){
        ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext_anno.xml");
        User user= (User) context.getBean("user");
        user.add();
    }

扩展:

Spring入门学习笔记

  • @Component
  • @Controller
  • @Service
  • @Repository

功能都一样,都是创建对象

2、注解注入属性

2.1 创建bookdao并注解

@Component("bookDao")
public class BookDao {
    public void add(String context) {
        System.out.println("数据库----add----" + context);
    }
}

2.2、创建bookservice并注解,需要注入的对象加上@Autowired注解

@Service(value = "bookService")
public class BookService {
    //拿到dao,作为bookservice属性(不需要实现set方法)
    //第一种、不常用
//    @Autowired //自动注入
//    private BookDao bookDao;

    //第二种,常用--->注入谁更加明确
    @Resource(name = "bookDao")
    private BookDao bookDao;

    public void add(String context) {
        System.out.println("------业务实现----add----------");
        bookDao.add(context);
    }
}

2.3、使用

  @Test
    public void testBookService() {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext_anno.xml");
        BookService user = (BookService) context.getBean("bookService");
        user.add("天龙八部");
    }

2.4、输出

------业务实现----add----------
数据库----add----天龙八部

2.5、总结

只需要一行代码配置注解扫描,不像每个都配置bean那么麻烦了

整个过程中,看不到new的过程,这对于后续代码的扩展好处很多

混合配置

学习过程中常用的方式(开发中就都用注解会更好点):

  • 1、创建对象一般使用配置文件来完成;

  • 2、注入属性一般使用注解来完成

AOP 面向切面编程

概述

效果:扩展功能,可以不通过修改原代码来实现

机制:aop采取横向抽取机制,取代传统纵向继承体系重复性代码(性能监视、事务管理、安全检查、缓存)

Spring Aop使用纯java实现,不需要专门的编辑过程和类加载器,在运行期间通过代理方式向目标类注入增强代码;

AspecJ是一个基于java语言的aop框架,Spring2.0开始就支持了,AspectJ扩展了java语言,提供了一个专门的编译器,在编译时提供横向代码的注入;

AOP原理(了解)

纵向机制

Spring入门学习笔记

横向机制

Spring入门学习笔记

aop操作术语

  • Joinpoint(连接点):类里面的方法可以被增强,这些方法称为连接点

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

    • 在类里面可以有很多方法可以被增强,比如实际操作中,只是增强了add和update,实际增强的方法称为切入点。
  • Advice(通知/增强):所谓通知是指拦截到joinpoint之后需要做的申请就是通知,通知分为前置通知、后置通知、异常通知、最终通知、环绕通知(切面要完成的功能)

    • 增强的逻辑,称为增强,比如扩展日志功能
    • 前置通知:方法之前执行
    • 后置通知:方法只会执行
    • 异常通知:方法出现异常
    • 最终通知:在后置之后
    • 环绕通知:在方法之前和之后都执行
  • Aspect(切面):是切入点和通知的结合

    • 把增强应用到具体的切入点方法上的过程

Spring入门学习笔记

aop操作

使用aspectj来实现aop

aspectj

本身不是spring的一部分,而是结合spring使用

是一个基于java语言的aop框架,Spring2.0开始就支持了,AspectJ扩展了java语言,提供了一个专门的编译器,在编译时提供横向代码的注入;

aspectj两种实现方式

操作前,需要导入aop的约束

1、配置xml文件

1.1、使用表达式配置切入点

execution(<访问修饰符>?<返回类型><方法名>(<参数>)<异常>)

- 访问修饰符:private public protacted等,使用*表示任何

eg1:execution(* com.hdl.ioc.day03.Book.add(..)) 类中指定方法

eg2:execution(* com.hdl.ioc.day03.Book.**(..)) 包中所有方法

eg3:execution(* *.*(..)) 所有包中所有方法

eg4:execution(* save.*(..)) 所有包含save开头的方法

1.2、开始配置

原有类:

public class Book {
    public void add(String name) {
        System.out.println("add-------" + name);
    }
}

为book类增加前置增强:

/**
 * book的增强类
 * Created by HDL on 2017/10/18.
 */
public class BookZQ {
    public void before() {
        System.out.println("前置增强.........");
    }
}

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:aop="http://www.springframework.org/schema/aop" 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
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
    <!--配置对象-->
    <bean id="book" class="com.hdl.ioc.day03.Book"/>
    <!--增强类-->
    <bean id="bookZQ" class="com.hdl.ioc.day03.BookZQ"/>
    <!--配置aop操作-->
    <aop:config>
        <!--配置切入点-->
        <aop:pointcut id="pointcut1" expression="execution(* com.hdl.ioc.day03.Book.*(..))"/>
        <!--配置切面(增强用到方法上)-->
        <aop:aspect ref="bookZQ">
            <!--配置method作用在pointcut上-->
            <aop:before method="before"  pointcut-ref="pointcut1"/>
        </aop:aspect>
    </aop:config>
</beans>

测试:

public class TestZQ {
    @Test
    public void testZQ(){
        ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext_aop.xml");
        Book book= (Book) context.getBean("book");
        book.add("哈利波特");
    }
}

输出:

前置增强.........
add-------哈利波特

新增方法:

public class Book {
    public void add(String name) {
        System.out.println("add-------" + name);
    }

    public void update(int id) {
        System.out.println("update-------" + 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:aop="http://www.springframework.org/schema/aop" 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
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
    <!--配置对象-->
    <bean id="book" class="com.hdl.ioc.day03.Book"/>
    <!--增强类-->
    <bean id="bookZQ" class="com.hdl.ioc.day03.BookZQ"/>
   <!--配置aop操作-->
      <aop:config>
          <!--配置切入点,第一个*之后有空格-->
          <aop:pointcut id="pointcut1" expression="execution(* *.*(..))"/>
          <!--配置切面(增强用到方法上)-->
          <aop:aspect ref="bookZQ">
              <!--配置method作用在pointcut上(前置增强)-->
              <aop:before method="before" pointcut-ref="pointcut1"/>
              <!--后置增强-->
              <aop:after-returning method="after" pointcut-ref="pointcut1"/>
              <!--环绕增强-->
              <aop:around method="arund" pointcut-ref="pointcut1"/>
          </aop:aspect>
      </aop:config>
</beans>

测试:

public class TestZQ {
    @Test
    public void testZQ(){
        ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext_aop.xml");
        Book book= (Book) context.getBean("book");
        book.add("哈利波特");
        book.update(1001);
    }
}

输出:

前置增强.........
方法前----------------
add-------哈利波特
方法后---------------
后置增强.........


前置增强.........
方法前----------------
update-------1001
方法后---------------
后置增强.........

2、注解方式

Spring入门学习笔记

2.1、配置自动代理和注解

<?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:aop="http://www.springframework.org/schema/aop"
       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
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
    <!--开启注解扫描
        会根据base-package填写的包名,扫描所有的属性、方法、类上是否有注解
   -->
    <context:component-scan base-package="com.hdl.ioc.day05"/>

    <!--自动代理,注解aop-->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

</beans>

2.2、原类(需要被增强的类)

/**
 * 原类(需要被增强的类)
 * Created by HDL on 2017/10/21.
 */
@Component("book")
public class Book {
    public void add(String bookName) {
        System.out.println("入库操作,操作编号:" + System.currentTimeMillis() + "\t书名:" + bookName);
    }

}

2.3 增强类

/**
 * 增强book类
 * Created by HDL on 2017/10/21.
 */
@Aspect//表示是增强类
@Component("bookZQ")
public class BookZQ {
    @Before(value = "execution(* com.hdl.ioc.day05.*.*(..))")
    public void addZqBefore() {
        System.out.println("入库时间:" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(System.currentTimeMillis())));
    }

    @After(value = "execution(* com.hdl.ioc.day05.*.*(..))")
    public void addZqAfte() {
        System.out.println("入库完成时间:" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(System.currentTimeMillis())));
    }
    @Around(value = "execution(* com.hdl.ioc.day05.*.*(..))")
    public void around(ProceedingJoinPoint process){
        System.out.println("方法执行前----------------");
        try {
            process.proceed();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        System.out.println("方法执行后---------------");

    }
}

2.4、测试

public class BookTest {
    @Test
    public void testBook(){
        ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext_aop_anno.xml");
        Book book= (Book) context.getBean("book");
        book.add("《明朝那些事》");
    }
}

2.5、结果

方法执行前----------------
入库时间:2017-10-21 23:02:56
入库操作,操作编号:1508598176859 书名:《明朝那些事》
方法执行后---------------
入库完成时间:2017-10-21 23:02:56

Log4J

程序运行过程中记录详细信息

配置:复制配置文件log4j.properties到src文件中

日志级别:

  • info 基本信息

  • debug 更详细信息

一个比较完整的Spring Demo

项目结构图:

Spring入门学习笔记

结果:

Spring入门学习笔记

导入必要的jar包(见结构图)

创建并配置spring的配置文件:applicationContext_web.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">
    <!--开启注解扫描
   会根据base-package填写的包名,扫描所有的属性、方法、类上是否有注解
   -->
    <context:component-scan base-package="com.hdl.ioc.day04"/>
    <!--用下面这个配置,只会扫描属性上面的注解-->
    <!--<context:annotation-config></context:annotation-config>-->
</beans>

配置web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">
    <!--配置Spring监听器,自动加载配置文件(避免每次访问servlet都需要加载一次配置文件,浪费资源)-->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:applicationContext_web.xml</param-value>
    </context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
</web-app>

创建userservlet

@WebServlet("/UserServlet")
public class UserServlet extends javax.servlet.http.HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");
        response.setCharacterEncoding("UTF-8");
        String username = request.getParameter("username");
        String pwd = request.getParameter("pwd");
        System.out.println(username+"\n"+pwd);
        ApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
        UserService userService = (UserService) context.getBean("userService");
        boolean registe = userService.registe(username, pwd);
        PrintWriter pw = response.getWriter();
        pw.write("username=" + username + "\n");
        pw.write("pwd=" + pwd + "\n");
        pw.write("是否注册成功:" + registe);
        pw.close();
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }
}

创建UserService

/**
 * 实际提供用户操作逻辑的地方
 * Created by HDL on 2017/10/21.
 */
@Service("userService")
public class UserService {
    //    @Autowired
    @Resource(name = "userDao")
    private UserDao userDao;

    public  boolean registe(String username, String pwd) {
        if (username == null || "".equals(username) || pwd == null || "".equals(pwd)) {
            return false;
        }
        return userDao.registe(username, pwd);
    }
}

创建UserDao

/**
 * 实际操作用户数据库的地方
 * Created by HDL on 2017/10/21.
 */
@Component("userDao")
public class UserDao {
    public boolean registe(String username, String pwd) {
        if ("admin".equals(username) && "132".equals(pwd)) {
            return true;
        } else {
            return false;
        }
    }
}

尊重原创,转载请注明出处,原文地址: http://blog.csdn.net/qq137722697