Spring

小结Spring

Spring下载

github下载:https://github.com/spring-projects/spring-framework/releases

<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.2.0.RELEASE</version>
</dependency>

Spring就是一个轻量级的控制反转(IOC)和面向切面(AOP)的框架!

第一个IOC程序

public class UserDaoImpl implements UserDao {
    public void getUser() {
        System.out.println("UserDaoImpl.......");
    }
}
public class UserDaoOracleImpl implements UserDao{
    public void getUser() {
        System.out.println("UserDaoOracleImpl.......");
    }
}
public class UserServiceImpl implements UserService{
//    private UserDao userDao = new UserDaoImpl();
    private UserDao userDao;
    //利用set进行动态实现值的注入
    public void setUserDao(UserDao userDao){
        this.userDao = userDao;
    }
    public void getUser() {
        userDao.getUser();
    }
}
<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="UserDaoImpl" class="com.kuang.dao.UserDaoImpl"/>
    <bean id="UserDaoOracleImpl" class="com.kuang.dao.UserDaoOracleImpl"/>

    <bean id="UserServiceImpl" class="com.kuang.service.UserServiceImpl">
        <property name="userDao" ref="UserDaoOracleImpl"/>
    </bean>
</beans>
public class TestIoc {
    public static void main(String[] args) {
        //获取ApplicationContext,拿到spring的容器
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
        //容器在手,天下我有,需要什么就直接get什么
        UserServiceImpl userServiceImpl = (UserServiceImpl)applicationContext.getBean("UserServiceImpl");
        userServiceImpl.getUser();
    }
}

IOC创建对象的方式

  1. 使用无参构造创建对象,默认
public class User {
    private String name;
    public User() {
        System.out.println("wucan........");
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="user" class="com.kuang.pojo.User">
<property name="name" value="kuangshen"/>
</bean>
</beans>
public class Test01 {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        User user = (User) context.getBean("user");
    }
}
  1. 假设我们要使用有参构造创建对象。

    • 下标赋值
    • 通过类型创建(不推荐)如果两个相同的入参就不行
    • 直接通过参数名来设置
public class User {
    private String name;
    public User(String name) {
        this.name = name;
        System.out.println("youcan........");
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}
//方法一:下标赋值
<bean id="user" class="com.kuang.pojo.User">
    <constructor-arg index="0" value="qiangjiang"/>
</bean>
//方法二:类型赋值
<bean id="user" class="com.kuang.pojo.User">
    <constructor-arg type="java.lang.String" value="kaungshne"/>
</bean>
方法三:参数名赋值(推荐使用)
<bean id="user" class="com.kuang.pojo.User">
    <constructor-arg name="name" value="kuangshen3"/>
</bean>
public class Test01 {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        User user = (User) context.getBean("user");
    }
}

总结:在配置文件加载的时候,容器中的对象就已经初始化了

别名

//两种方式
//
<bean id="user" class="com.kuang.pojo.User" name="u1,u2,u3,u4,u5">
    <!--<constructor-arg index="0" value="qiangjiang"/>-->
    <!--<constructor-arg type="java.lang.String" value="kaungshne"/>-->
    <constructor-arg name="name" value="kuangshen3"/>
</bean>
<alias name="user" alias="u0"/>

Import

将不同的beans.xml合并到一个applicationContext.xml中,在applicationContext.xml中用import导入

<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
        https://www.springframework.org/schema/beans/spring-beans.xsd">
    <import resource="beans.xml"/>
    <import resource="beans1.xml"/>
    <import resource="beans2.xml"/>
</beans>

依赖注入

  1. 构造器注入
  2. Set方式注入【重点】
public class Student {
    private String name;
    private Address address;
    private String[] books;
    private List<String> hobbys;
    private Map<String,String> card;
    private Set<String> games;
    private String wife;
    private Properties info;
public class Address {
    private String address;
<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="address" class="com.kuang.pojo.Address">
        <property name="address" value="jiangsu"/>
    </bean>
    <bean id="student" class="com.kuang.pojo.Student">
        <property name="name" value="qingjang"/>
        <property name="address" ref="address"/>
        <property name="books">
            <array>
                <value>红楼梦</value>
                <value>水浒传</value>
                <value>西游记</value>
                <value>三国演义</value>
            </array>
        </property>
        <property name="hobbys">
            <list>
                <value>听歌</value>
                <value>看电影</value>
                <value>敲代码</value>
            </list>
        </property>
        <property name="card">
            <map>
                <entry key="身份证" value="321088199292929292"/>
                <entry key="电话" value="32108819929"/>
            </map>
        </property>
        <property name="games">
            <set>
                <value>LOL</value>
                <value>炉石</value>
                <value>云顶之奕</value>
            </set>
        </property>
        <property name="wife">
            <null/>
        </property>
        <property name="info">
            <props>
                <prop key="driver">com.mysql.jdbc.Driver</prop>
                <prop key="url">jdbc:mysql://localhost:3306/mybatis?useSSL=true&amp;useUnicode=true&amp;characterEncoding=UTF-8</prop>
                <prop key="username">root</prop>
                <prop key="password">123456</prop>
            </props>
        </property>
    </bean>
</beans>
public class TestDI {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
        Student student = (Student) context.getBean("student");
        Student student2 = (Student) context.getBean("student");
        System.out.println(student==student2);
    }
}

bean的作用域

  1. 单例模式(spring的默认机制)
<bean id="student" class="com.kuang.pojo.Student" scope="singleton">
  1. 原型模式
<bean id="student" class="com.kuang.pojo.Student" scope="prototype">
  1. 其余的request、session、application这些只能在web开发中使用到!

Bean的自动装配

  • 自动装配是Spring满足bean依赖一种方式!
  • Spring会在上下文中自动寻找,并自动给bean装配属性!

在Spring中有三种装配的方式

  1. 在xml中显式地配置
  2. 在java中显式配置
  3. 隐式地自动装配【重点】

@Autowired

public class People {
    private String name;
    @Autowired
    private Dog dog;
    @Autowired
    private Cat cat;
<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd">
    <context:annotation-config/>

    <bean id="dog" class="com.kuang.pojo.Dog"/>
    <bean id="cat" class="com.kuang.pojo.Cat"/>
    <bean id="people" class="com.kuang.pojo.People"/>

</beans>
public class Test01 {
    @Test
    public void test01(){
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        People people = context.getBean("people", People.class);
        people.getCat().shout();
        people.getDog().shout();
    }
}
  • @Autowired 直接在属性上使用即可!也可以在set方式上使用!使用Autowired 我们可以不用编写Set方法了,前提是你这个自动装配的属性在IOC(Spring)容器中存在,且符合名字ByName!

  • 如果@Autowired自动装配的环境比较复杂,自动装配无法通过一个注解【@Autowired】完成的时候,我们可以使用@Qualifier(value="xxx")去配置@Autowired的使用,指定一个唯一的bean对象注入!

public class People {
    private String name;
    @Autowired
    @Qualifier(value = "dog11")
    private Dog dog;
    @Autowired
    @Qualifier(value = "cat11")
    private Cat cat;
<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd">
    <context:annotation-config/>
    <bean id="dog11" class="com.kuang.pojo.Dog"/>
    <bean id="dog22" class="com.kuang.pojo.Dog"/>
    <bean id="cat11" class="com.kuang.pojo.Cat"/>
    <bean id="cat22" class="com.kuang.pojo.Cat"/>
    <bean id="people" class="com.kuang.pojo.People"/>
</beans>

required = true(不写默认是true)
这个表示:注入bean的时候该bean必须存在,不然就会注入失败!

Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.kuang.pojo.Dog' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}

required = false
这个表示:注入bean的时候如果bean存在,就注入成功,如果没有就忽略跳过,启动不会报错!但是不能直接使用,因为doRequiredTest为NULL!

@Resource

<bean id="dog11" class="com.kuang.pojo.Dog"/>
<bean id="dog22" class="com.kuang.pojo.Dog"/>
<bean id="cat11" class="com.kuang.pojo.Cat"/>
<bean id="cat22" class="com.kuang.pojo.Cat"/>
<bean id="people" class="com.kuang.pojo.People"/>
public class People {
    private String name;
    @Resource
    private Dog dog;
    @Resource
    private Cat cat;
public class Test01 {
    @Test
    public void test01(){
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        People people = context.getBean("people", People.class);
        people.getCat().shout();
        people.getDog().shout();
    }
}

两个dog,cat的bean会报错

Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.kuang.pojo.Dog' available: expected single matching bean but found 2: dog11,dog22

resource先根据id,再通过class,因为这里ByName匹配不到,class又有两个,所以报错

解决:通过@Resource(name = "")指定

public class People {
    private String name;
    /*@Autowired
    @Qualifier(value = "dog11")*/
    @Resource(name = "dog11")
    private Dog dog;
    /*@Autowired
    @Qualifier(value = "cat11")*/
    @Resource(name = "cat11")
    private Cat cat;

小结:

@Autowired和@Resource的区别:

  • 都是用来自动装配的,都可以放在属性字段上

  • @Autowired 通过ByName的方式实现,而且必须要求这个对象存在(除非构造方法有@Nullable)

    public People(@Nullable String name) {
        this.name = name;
    }
    
  • @Resource 通过ByType的方式实现,如果找不到名字,则通过ByType实现!如果两个都找不到就报错

@Component

@Component有几个衍生注解,我们在web开发中,会按照mvc三层架构分层

  • dao 【@Repository】
  • service 【@Service】
  • controller 【@Controller】

这四个注解功能都是一样的,都是代表将某个类注册到Spring中,装配Bean

注意的问题:想让注解生效,就必须开启注解的支持

<!--指定要扫描的包,这个包下的注解就会生效-->
<context:component-scan base-package="com.kuang"/>
<context:annotation-config/>

拦截器

  1. 新建一个Moudule , springmvc-07-Interceptor , 添加web支持
  2. 配置web.xml 和 springmvc-servlet.xml 文件,添加jar包
<?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_4_0.xsd"
         version="4.0">
    <servlet>
        <servlet-name>springmvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:applicationContext.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

    <filter>
        <filter-name>encodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>utf-8</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>encodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
</web-app>
<?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"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
    <!--自动扫描指定的包,下面所有注解类交给IOC容器管理-->
    <context:component-scan base-package="com.kuang.controller"/>

    <!--静态资源过滤-->
    <mvc:default-servlet-handler/>

    <!--JSON乱码问题配置-->
    <mvc:annotation-driven>
        <mvc:message-converters register-defaults="true">
            <bean class="org.springframework.http.converter.StringHttpMessageConverter">
                <constructor-arg value="UTF-8"/>
            </bean>
            <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
                <property name="objectMapper">
                    <bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean">
                        <property name="failOnEmptyBeans" value="false"/>
                    </bean>
                </property>
            </bean>
        </mvc:message-converters>
    </mvc:annotation-driven>

    <!--4.视图解析器-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <property name="suffix" value=".jsp"/>
    </bean>
  
</beans>

编写一个拦截器

public class MyInterceptor implements HandlerInterceptor {
    //在请求处理的方法之前执行
    //如果返回true执行下一个拦截器
    //如果返回false就不执行下一个拦截器
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("------------处理前------------");
        return true;
    }

    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("------------处理后------------");
    }

    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("------------清理------------");
    }
}

在applicationContext.xml的配置文件中配置拦截器

<!--关于拦截器的配置-->
<mvc:interceptors>
    <mvc:interceptor>
        <!--/** 包括路径及其子路径-->
        <!--/admin/* 拦截的是/admin/add等等这种 , /admin/add/user不会被拦截-->
        <!--/admin/** 拦截的是/admin/下的所有-->
        <mvc:mapping path="/**"/>
        <!--bean配置的就是拦截器-->
        <bean class="com.kuang.config.MyInterceptor"/>
    </mvc:interceptor>
</mvc:interceptors>

编写控制器

@Controller
public class InterceptorController {
    @RequestMapping("/interceptor")
    @ResponseBody
    public String testFunction() {
        System.out.println("控制器中的方法执行了");
        return "hello";
    }
}

前端 index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>$Title$</title>
  </head>
  <body>
  <a href="${pageContext.request.contextPath}/interceptor">拦截器测试</a>
  </body>
</html>

ok

posted @ 2021-04-17 21:17  血^_^月  阅读(47)  评论(0)    收藏  举报