Spring复习笔记

概述

spring是javaee轻量级开源框架;

spring有两个最核心的模块: IOC和AOP;

IOC:(inverse of control) ,控制反转,将创建对象的过程交给spring进行管理;

AOP:(Aspect Oriented Programming),面向切面编程。aop用来封装多个类的公共行为。

入门程序

//引入spring-context依赖
<dependency>
     <groupId>org.springframework</groupId>
     <artifactId>spring-context</artifactId>
     <version>5.3.26</version>
</dependency>

//创建一个user类
package com.zhang;
public class user {
    public void add(){
        System.out.println("this is a add method");
    }
}

//配置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">
<!--  
    id:唯一标识
    class:要创建对象所在类的全路径
-->
    <bean id="user" class="com.zhang.user"></bean>
</beans>

//通过读取配置文件创建user对象
package org.example;
import com.zhang.user;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context  = new ClassPathXmlApplicationContext("bean.xml");
        user user = (user)context.getBean("user");
        System.out.println(user);
        user.add();
    }
}

如何使用反射创建对象?

1.加载bean.xml配置文件

2.对xml文件进行解析

3.获取xml文件bean标签属性值

4.使用反射根据类的全路径创建对象

 Class clazz = class.forName("com.Xxx.xxx");

(User) user =  (User)clazz.getDeclaredConstructor().newInstance();

创建的对象放到哪里?

Map<String,BeanDefinition> beanDefinitionMap

其中key:唯一标识,value:类的定义(描述信息)

Apache Log4j2

开源的日志记录组件;

log4j2组成:

  1. 日志信息的优先级
  2. 日志信息的输出目的地
  3. 日志信息的输出格式
<--依赖-->
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>2.13.3</version>
</dependency>
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-slf4j-impl</artifactId>
    <version>2.13.3</version>
</dependency>

<?xml version="1.0" encoding="UTF-8"?>
 <!--日志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL -->
 <!--Configuration后面的status,这个用于设置log4j2自身内部的信息输出,可以不设置,当设置成trace时,你会看到log4j2内部各种详细输出-->
 <!--monitorInterval:Log4j能够自动检测修改配置 文件和重新配置本身,设置间隔秒数-->
 <configuration status="WARN" monitorInterval="30">
     <!--先定义所有的appender-->
     <appenders>
     <!--这个输出控制台的配置-->
         <console name="Console" target="SYSTEM_OUT">
         <!--输出日志的格式-->
             <PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/>
         </console>
     <!--文件会打印出所有信息,这个log每次运行程序会自动清空,由append属性决定,这个也挺有用的,适合临时测试用-->
     <File name="log" fileName="log/test.log" append="false">
        <PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n"/>
     </File>
     <!-- 这个会打印出所有的info及以下级别的信息,每次大小超过size,则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档-->
         <RollingFile name="RollingFileInfo" fileName="${sys:user.home}/logs/info.log"
                      filePattern="${sys:user.home}/logs/$${date:yyyy-MM}/info-%d{yyyy-MM-dd}-%i.log">
             <!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)-->        
             <ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/>
             <PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/>
             <Policies>
                 <TimeBasedTriggeringPolicy/>
                 <SizeBasedTriggeringPolicy size="100 MB"/>
             </Policies>
         </RollingFile>
         <RollingFile name="RollingFileWarn" fileName="${sys:user.home}/logs/warn.log"
                      filePattern="${sys:user.home}/logs/$${date:yyyy-MM}/warn-%d{yyyy-MM-dd}-%i.log">
             <ThresholdFilter level="warn" onMatch="ACCEPT" onMismatch="DENY"/>
             <PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/>
             <Policies>
                 <TimeBasedTriggeringPolicy/>
                 <SizeBasedTriggeringPolicy size="100 MB"/>
             </Policies>
         <!-- DefaultRolloverStrategy属性如不设置,则默认为最多同一文件夹下7个文件,这里设置了20 -->
             <DefaultRolloverStrategy max="20"/>
         </RollingFile>
         <RollingFile name="RollingFileError" fileName="${sys:user.home}/logs/error.log"
                      filePattern="${sys:user.home}/logs/$${date:yyyy-MM}/error-%d{yyyy-MM-dd}-%i.log">
             <ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY"/>
             <PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/>
             <Policies>
                 <TimeBasedTriggeringPolicy/>
                 <SizeBasedTriggeringPolicy size="100 MB"/>
             </Policies>
         </RollingFile>
     </appenders>
     <!--然后定义logger,只有定义了logger并引入的appender,appender才会生效-->
     <loggers>
         <!--过滤掉spring和mybatis的一些无用的DEBUG信息-->
         <logger name="org.springframework" level="INFO"></logger>
         <logger name="org.mybatis" level="INFO"></logger>
         <root level="all">
             <appender-ref ref="Console"/>
             <appender-ref ref="RollingFileInfo"/>
             <appender-ref ref="RollingFileWarn"/>
             <appender-ref ref="RollingFileError"/>
         </root>
     </loggers>
 </configuration>

容器IOC

        IOC(Inversion of Control):控制反转,是一种思想;Spring通过IOC容器来管理 所有Java对象的实例化和初始化,控制对象与对象间的依赖关系; 将IOC容器管理的Java对象称为Spring bean;

        Spring创建IOC容器的方式:Beanfactory(内部开发人员用) ApplicationContext(子接口);

依赖注入DI

        DI(Dependency injection):依赖注入,依赖注入实现了控制反转思想。

        依赖注入指spring创建对象的过程中,将对象依赖属性通过配置进行注入;

        依赖注入常见的两种方式:set注入,构造注入;

基于xml管理bean

1.获取bean

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

方式一:根据id获取

User user = (User)context.getBean("bean_id");

方式二:根据类型获取

//根据类型获取,要求IOC容器中指定类型的bean只能有一个
User user = context.getBean(User.class);

方式三:根据id和类型获取

User user = context.getBean("user",User.class);

注意:

        如果组件类实现了接口并且bean唯一,可以根据接口类型获取bean;

如果一个接口有多个实现类,这些实现类都配置了bean,不可以根据接口类型获取bean;

2.依赖注入

1.setter注入

<?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">
    <bean id="user" class="com.zhang.user">
        <property name="name" value="zhangsan"></property>
    </bean>
</beans>

<--
使用property 属性
name是属性名
value是要赋的值
-->

2.构造器注入

<bean id="Xxx" class = "Xxx">
<constructor-arg name="Xxx" value="Xxx"></constructor-arg>
</bean>

3.特殊值处理

<--null-->
<property name="abc">
</null>
</property>

<--xml实体-->
<property name="abc" value" &lt;&gt;"></property>

<--xml解析看到cdata节就知道里面的内容是纯文本,不会当作xml标签或属性来处理-->
<property name="abc">
<value>
<![CDATA[ <> ]>
</value>
</property>

4.为对象类型属性赋值

<--
a类中的属性b的数据类型是引用数据类型,用如下方法为属性b赋值
方式一:外部bean
-->
<property name = "属性b" ref = "b的bean_id"></property>

<--方式二:内部bean-->
<property name ="">
<bean id = "" class="">
...
</bean>
</property>

<--级联赋值-->

 5.为数组类型属性赋值

<bean id ="" class="">
<property name="">
    <array>
        <value></value>
        ...
        <value></value>
    </array>
</property>
</bean>

6.集合类型属性赋值

<!--List类型属性-->
<bean id = "" class="">
    <property name="">
     <list>
      <ref bean=""></ref>
        ...
      <ref bean=""></ref>
     </list>
    </property>
</bean>

<!--Map类型属性-->
<bean id = "" class="">
    <property name="">
     <map>
        <entry>
         <key>
            <value>xxx</value>
         </key>
         <ref bean="bean_id"></ref>
        </entry>
     </map>
    </property>
</bean>

<!--引入集合bean-->
<util:list id="">
    <ref bean=""></ref>
    <ref bean=""></ref>
</util:list>


<util:map id="">
<entry>
         <key>
            <value>xxx</value>
         </key>
         <ref bean="bean_id"></ref>
        </entry>
</util:map>

6.p命名空间 

配置

<

beans xmlns:p="http://www.springframework.org/schema/p"

...

>

<bean id="" calss="" p:xxx="" p:xxx=""></bean>

<beans>

7.引入外部属性文件

 //配置文件中 添加xmlns:context相关 配置
<?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">
    <--加载bean- out.properties-->
    <context:property-placeholder location="bean-out.properties"></context:property-placeholder>
    <bean id="user" class="com.zhang.user">
    <--通过${} 获取值-->
        <property name="name" value="${s.name}"></property>
    </bean>
</beans>

8.bean的作用域

 在Spring中通过配置bean标签的scope属性来指定bean的作用域范围

取值含义创建对象的时机
singleton(默认)在ioc容器中,这个bean的对象始终为单例ioc容器初始化时
prototype这个bean在ioc容器中有多个实例获取bean时

9.bean生命周期

  1. bean对象创建(调用无参构造器)
  2. 给bean对象设置相关属性
  3. bean后置处理器(初始化前)
  4. bean对象初始化
  5. bean后置处理器(初始化后)
  6. bean对象创建完成
  7. bean对象销毁
  8. IoC容器关闭

10.FactoryBean

整合第三方框架

......

实现FactoryBean接口

11.基于xml自动装配

<bean id="" class="" autowire="byType"></bean>

 byType:根据类型匹配IOC容器中的某个兼容类型的bean,为其自动赋值;

<bean id="" class="" autowired="byName"></bean>

byName:

基于注解管理bean

1.开启组件扫描

xml方式

<context:component-scan base-package="包名"></comtext:component-scan>

注解方式

2.使用注解定义bean

注解说明
@Component用于描述Spring中的bean
@Repository用于将数据访问层的类标识为bean
@Service用于将业务层的类标识为bean
@Controller用于将控制层的类标识为bean

3.注入

@Autowired注入

//1.属性注入
@Autowired
private User user;

//2.set方法注入
private User user;
@Autowired
public void setUser(User user){
...
}

//3.构造方法注入
private User user;
@Autowired
public User(){
...
}

//4.形参注入
private User user;
public User(@Autowired Name name){
...
}

//5.只有一个有参数构造函数,@Autowired可以省略

//6.@Autowired和@Qualifier联合使用,指定bean名称

@Resource注入

@Resource注解是jdk扩展包中的。更加具有通用性。

会默认根据byName,未指定name时,使用属性名作为name。通过name找不到会通过byType装配。

使用位置:属性,setter方法

4.配置类替代配置文件

package com.zhang.config;

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

@Configuration
@ComponentScan("com.zhang")
public class config {
}

 手写IoC

创建两个注解(创建对象,属性注入);

创建bean容器接口ApplicationContext定义方法,返回对象;

实现bean容器接口(返回对象,根据包规则加载bean);

需要自定义两个注解,用来标识 创建对象Bean和依赖注入DI

package com.zhang.bean;

import com.zhang.anno.Bean;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.net.URLDecoder;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

public class AnnotationApplicationContext implements ApplicationContext{

    //创建map集合,存放bean对象
    private static Map<Class,Object> beanFactory = new HashMap<Class,Object>();

    //
    private static String rootPath;
    //返回对象
    @Override
    public Object getBean(Class clazz) {
        return null;
    }
    //创建有参构造器,传递包路径,设置包扫描规则

    public AnnotationApplicationContext(String basePackage){

        //1.把包名中的.替换成/
        String packagePath = basePackage.replaceAll("\\.", "\\\\");

        //2.获取包绝对路径
        try {
            Enumeration<URL> urls = Thread.currentThread().getContextClassLoader().getResources(packagePath);
            while(urls.hasMoreElements()){
                URL url = urls.nextElement();
                String filepath = URLDecoder.decode(url.getFile(), "utf-8");
                rootPath = filepath.substring(0, filepath.length() - packagePath.length());
                //包扫描
                try {
                    loadBean(new File(rootPath));
                } catch (ClassNotFoundException e) {
                    throw new RuntimeException(e);
                } catch (NoSuchMethodException e) {
                    throw new RuntimeException(e);
                } catch (InvocationTargetException e) {
                    throw new RuntimeException(e);
                } catch (InstantiationException e) {
                    throw new RuntimeException(e);
                } catch (IllegalAccessException e) {
                    throw new RuntimeException(e);
                }
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }

    private static void loadBean(File file) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {


        //1.判断是否为文件夹
        if(file.isDirectory()){
            //2.获取文件夹里所有内容
            File[] childFiles = file.listFiles();
            //3.判断文件夹为空,直接返回
            if(childFiles == null || childFiles.length == 0){
                return;
            }

            //4.不为空遍历文件夹所有内容
            for(File child : childFiles){
                //4.1 遍历每个File对象,如果是文件夹递归

                if(child.isDirectory()){
                    loadBean(child);
                }else
                //4.2 是文件
                {
                    //4.3 得到包路径+类名称部分
                    String pathWithClass = child.getAbsolutePath().substring(rootPath.length() - 1);

                    //4.4 判断当前文件类型是否为 .class
                    if(pathWithClass.contains("class")){
                        //4.5 如果是.class,把路径\替换成. 把.class去掉

                        String allName = pathWithClass.replaceAll("\\\\", "\\.")
                                .replace(".class", "");

                        //4.6 判断类上是否有注解@Bean
                        //4.6.1 获取类的class对象
                        Class<?> aClass = Class.forName(allName);
                        //4.6.2 是否为接口
                        if(aClass.isInterface()){
                            return;
                        }
                        Bean annotation = aClass.getAnnotation(Bean.class);
                        if(annotation != null){

                            //4.7 把对象实例化之后,放到map集合中
                            Object instance = aClass.getConstructor().newInstance();
                            //判断当前类是否有接口
                            if(aClass.getInterfaces().length > 0){
                                beanFactory.put(aClass.getInterfaces()[0],instance);
                            }else{
                                beanFactory.put(aClass,instance);
                            }
                        }

                    }

                }

            }

        }

    }

}

面向切面AOP

代理模式

静态代理

动态代理(aop底层)

AOP概述

AOP(Aspect Oriented Programming)是一种设计思想。通过预编译方式和运行期动态代理方式实现,在不修改源代码的情况下,给程序动态统一添加额外功能的一种技术。

动态代理分类

有接口,使用jdk动态代理,生成接口实现类代理对象

没有接口,使用cglib动态代理,生成子类代理对象

 <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>5.3.26</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>6.0.2</version>
        </dependency>
    </dependencies>

基于注解的aop

通知类型

@Before

@AfterReturning

@AfterThrowing

@After

@Around

基于xml的aop


未完待续  57中间/88         // 2024年3月26日 

  • 13
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值