【自用学习笔记】初学spring


【学习视频来自b站江南一点雨,推荐所有新手去看,讲得超棒】
将Bean注册到Spring容器中有三种方法:

​ 1.xml注入

​ 2.Java配置

​ 3.自动化扫描

获取bean步骤

​ 1.引入依赖

​ 2.添加配置文件xml

​ 3.创建实体类,在xml中添加bean标签

​ 4.用ClassPathXmlApplicationContext(configLocation)导入配置文件,加载容器,获取对象

​ 4.1用getBean获取对象,按名字获取对象,强转

​ 4.2用getBean获取对象,按名字和class

​ 4.3 用getBean获取对象,用class获取(当xml中有两个Bean时就会报错)

User user1 =(User) ctx.getBean("user");
User user2=ctx.getBean("user",User.class);
User user3 = ctx.getBean(User.class);

​ 注意:用这3种方法获取的实例都是同一个

​ 或者用FileSystemXmlApplicationContext(”文件路径“) 使用场景较少

属性注入

1.构造方法注入

1.1通过name注入,在bean标签中添加

<constructor-arg name="id" value="1"/>

2.通过Set方法注入

2.1添加 最常用

<property name="address" value="address1"/>

这种本质上是调用了set方法

2.2 p名称空间 ,本质上是调用了set方法

xmlns:p="http://www.springframework.org/schema/p"
<bean class="com.text.ioc.model.User" id="user3" p:userName="name3" p:address="address3" p:id="3">
</bean>

快捷键alt+回车

注意:所有框架中涉及到反射注入值的,属性名都是java中的内省机制分析出来的属性名,即:根据get\set方法分析出的属性名

3.外部方法注入

适用于当使用外部的、没有构造方法的Bean时(如通过builder构造的Request、OkHttpClient等实例)

3.1使用静态工厂注入

​ 1.提供一个静态工厂

private static OkHttpClient OkHttpClient;
private static get(){
 写静态的get方法:如果没有工厂,就new OkHttpClient.Bulider().build();
}

​ 2.在xml中配置工厂

<bean class="org.text.OkHttpUtils" factory-method="get" id="okHttpClient"/>

​ 3.获取实例并使用

3.2 实例工厂注入

​ 工厂方法是一个实例方法,所以工厂类必须实例化之后才可以调用

<bean class="org.text.OkHttpUtils" id="okHttpUtils"/>
<bean class="okHttp3.OkHttpClient" factory-bean="okHttpUtils" factory-method="get" id="okHttpClient"/>

4.对象注入

​ 用name和ref

5.数组注入

​ property中添加标签 或者

​ value 字符串;对象:ref引用bean 套一层bean或引用外面的bean

Map:

<property name="details">
	<map>
		<entry key="gender" value="男"/>
    <map/>
<property/>

properties:

<property name="info">
	<props>
    	<prop key=phone>12345678</prop>
    <props/>
<property/>

java配置

有Spring Boot出现之后更常用

​ 1.编写实例

​ 2.创建Java配置类(即在类上面加@Configuration),new对象

@Configuration
public class JavaConfig{
	@Bean
    SayHello sayHello(){
        return new SayHello;
    }
}

​ 3.使用:new AnnotationConfigApplicationContext(JavaConfig.class)获得容器对象,用对象getBean

自动化配置

主要是利用自动化扫描(包扫描),用注解;自动扫描可以用Java配置,也可以用xml配置

​ @Service 用在service层

​ @Repository 用在DAO层

​ @Controller 用在controller层

​ @Component 用在其它层

用Java配置:

​ 1.写各层的代码,加对应的注解

​ 2.在javaConfig配置文件里加注解 @ComponentScan(basePackages=“要扫描的包名”)

​ 不指定包名会扫描配置文件所在包及 所在包的子类下所有文件

​ 3.获得容器对象,getBean通过类型或名字获取(默认是首字母小写的类名,也可以在注解中自定义名字)

注意:

在注解 @ComponentScan(basePackages="要扫描的包名",useDefaultFilter=true)

useDefaultFilter默认的扫描方式,默认为true,四类注解全部扫描

当useDefaultFilter设置为false,用includeFilters={@ComponentScan.Filter(type=FilterType.ANNOTATION,class=Service.class)}设置只扫描service注解

excludeFilters 除了写的都扫

用xml配置

​ 1.在前加

<context:component-scan base-package="要扫描的包" use-default-filters="false">
    <context:include-filter type="annotation" expression="org.springframework.stereotype.Service"
</context:component-scan>

​ 2.加载xml文件,getBean

对象注入

​ 自动扫描时对象注入有三种方式:

@Autowerid 根据类型查找,要求一个类型只有一个对象;配合@Qualifier 才可以指定变量名

@Resources 根据名称查找,默认定义的变量名就是查找的名称,也可在注解中自定义名称;适合多个实例

@Injected 较少使用

条件注解

@condition 指 在满足某一个条件的情况下生效的配置

​ 1.编写接口和不同条件下运行的实体类

​ 2.定义两个condition类,impl 实现spring中condition的方法(matches)

​ 2.1;获取操作系的名字

 String osName=conditionContext.getEnviroment().getProperty("os.name")

​ 2.2如果操作系统名称正确则返回true

return osName.toLowerCase().contains("win");

​ 3.配置实体类

@Configuration
public class JavaConfig{
	@Bean("cmd")
    @Condition(WindowCondition.class)
	ShowCmd winCmd{
        return new WindowShowCmd();
    }
	@Bean("cmd")
    @Condition(LinuxCondition.class)
	ShowCmd linuxCmd{
        return new LinuxShowCmd();
    }
}

​ 4.使用时 获取context ,getBean获取cmd

多环境切换

@Profile 底层基于条件注解,用于多环境(生产、测试)切换

Java中配置

​ 1.准备dataSource实体类(包含url、username、password)

​ 2.配置文件中写

@Configuration
public class JavaConfig{
	@Bean
    @Profile("dev")
    DataSource devDS(){
        DataSource ds=new DataSource();
        ds.setUrl("");
        ds.setUsername("");
        ds.setPassword("");
        return ds
    }
    @Bean
    @Profile("prod")
    DataSource proDS(){
        DataSource ds=new DataSource();
        ds.setUrl("");
        ds.setUsername("");
        ds.setPassword("");
        return ds
    }
  
}

​ 3.创建容器ctx(不要根据配置,直接new一个新的)

​ 3.1 设置activeProfiles ,导入配置文件,刷新容器

ctx.getEnviroment.setActiveProfiles(“prod);
ctx.register(JavaConfig.class);
ctx.refresh();

​ 3.2使用时改setActiveProfiles的内容即可

xml配置

​ 1.准备dataSource实体类

​ 2.配置文件中写

<beans profile="dev">
    <bean class="DataSource" id="devDs">
        <property name="url" value=""/>
        <property name="username" value=""/>
        <property name="password" value=""/>
    </bean>
</beans>
        
<beans profile="prod">
    <bean class="DataSource" id="devDs">
        <property name="url" value=""/>
        <property name="username" value=""/>
        <property name="password" value=""/>
    </bean>
</beans>

​ 3.main中加载,先new空的 ClassPathXmlApplicationContext();,再设置环境、引入配置文件、刷新容器、获取Bean

ctx.getEnviroment().setActiveProfiles("prod");
ctx.setConfigLocation("applicationContext.xml");
ctx.refresh();
DataSource ds=ctx.getBean(DataSource.class);

Bean的作用域

默认时,一个容器中有一个实例(scope=“singleton”)

xml中

bean标签中加 scope=“prototype” ,这个bean再容器中就不是单例,多次获取将拿到多个不同的实例

scope=“request” 在web环境下有效

scope=“session” 在web环境下有效

Java中

单例默认不加,代码中加@Scope(“prototype”) ,多次获取将拿到多个不同的实例

id和name的区别

大部分情况下一一昂

name支持多个,多个name之间用 , 隔开

id是唯一的

混合配置

就是把Java配置和xml配置混到一起,

在Java配置的那个类上额外加注解@ImportResource(“classpath:applicationContext.xml”)

容器加载安装Java加载(AnnotationConfigApplicationContext)

Aware接口

​ 用来获取容器的各种信息(比如配置文件的信息)

​ 1.依赖就是spring的依赖

​ 2.实现BeanNameAware(获取名称),BeanFactoryAware(获取工厂),ResourceLoadAware(获取资源加载器),EnvironmentAware(获取环境),注解@PropertySource(“要加载的文件名字”)

​ 3.私有变量beanName,resourceLoader,enviroment

注意:用了aware接口后,代码与容器的耦合会增大;比较少用

AOP

面向切面编程,是对面向对象思想的补充;可以做到在程序运行时,不改变源代码,动态增强方法的功能

如:日志、事务、数据库操作等等

常见概念

切点:要添加代码的地方

通知(增强advance):向切点动态添加的代码

切面:切点+通知

连接点:切点的定义(告诉spring怎么去定位到切点)

AOP的实现

本质基于Java动态代理实现

有两种方式:jdk,cglib

动态代理

方法不改变,在方法上加东西

​ 1.定义接口(MyCalculator)、实现(MyCalculatorImpl)、代理类(MyCalculatorproxy),实现中写方法

​ 2.代理类中定义方法

public class CalculatorProxy{
    public static Object(MyCalculator myCalculator){
        return Proxy.newProxyInstance(MyCalculator.class.getClassLoder(),myCalculator.getClass().getInterfaces(),new InvocationHandler){
            public Object invoke(Object proxy,Method method,Object[] args) throws Throwable{
                System.out.println(method.getName()+"方法开始执行了");
                Objetc invooke = method.invoke(myCalculator,args);
                System.out.println(method.getName()+"方法执行结束了");
                return invoke;
            }
        }
    }
}

其中:proxy:代理对象;method:代理的方法;args:方法的参数;return:方法的返回值

​ 3.调用时先new实现,再用proxy的方法传入实现获得实体类,再使用方法

MyCalculatorImpl myCalculator =new MyCalculatorImpl();
MyCalculator calculator =(MyCalculator)CalculatorProxy.getInstance(myCalculator);
int add=calculator.add(3,4);
System.out.println("add="+add);

AOP中的五种通知

前置通知、后置、异常、返回、环绕

JAVA配置使用时:

​ 1.项目中加依赖:spring-cintext、aspectjrt、aspectjweaver

​ 2.写接口、实现类(@Component 注解,扫描成实体类)

​ 3.定义切点

​ 3.1使用自定义注解(会入侵代码,少用)

​ ①自定义注解 @Action ,注解上加

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)

​ ②在要拦截方法上加@Action

​ ③定义增强(通知、Advice):

@Component
@Aspect //表示这是一个切面
public class LogAspect{
    //前置通知 在目标方法执行之前执行
    @Before(value="@annotation(xxx.xxx.xxx.Action)")
    public viod before(JoinPoint joinPoint){
        //前置通知的方法,可以打印日志
        //获取方法名
        String name =jiontPoint.getSignature().getName();
        //打印
        System.out.pringln(name+"方法开始执行了");
    }
    
    //后置通知,在目标方法执行之后执行
    @After("@annotation(Action)")
    public viod after(JoinPoint joinPoint){
        //后置通知的方法,可以打印日志
    }
    
    //返回通知,在该方法中获取目标方法的返回值
    @AfterReturning(value="@annotation(Action)",returning="r")
     public viod returning(JoinPoint joinPoint,Object r){
        //返回通知的方法,可以打印日志
        // returning是方法的返回值,没有返回类型不匹配则不显示;Objcet可以匹配所有的返回值类型
        //如果无返回值(viod),返回参数类型是Object,会有通知,返回值是null
    
    
    //异常通知,目标方法抛出异常时,此方法会触发
    @AfterThrowing(value="@annotation(Action)",throwing="e")
     public viod returning(JoinPoint joinPoint,Exception e){
        //返回通知的方法,可以打印日志
        // throwing e 异常参数,和方法的参数名一一对应,注意异常的类型,匹配不上则不显示
        }
    
    //环绕通知(集大成者,可以实现上面的四个通知,注意参数和别的不一样;核心类似于通过反射执行方法)
    @Aorund("@annotation(Action)")
    public Object around(ProceedingJoinPoint pjp){
        Object proceed=null;
        try{
            //类似于method.invoke,可以在这个方法的前、后分别添加日志,前置/后置通知;不写的话目标方法就不会执行
            //pjp.proceed(new Object[]{5,5})可以改参数
            proceed=pjp.proceed();
        }catch(Throwable throwable){
            //捕获异常,会有异常通知
            throwable.printStackTrace();
        }
        return proceed;
    }  
 
}

​ ④在JavaConfig(配置类)中开启包扫描和自动代理

@Configuration
@ComponentScan
@EnableAspectJAutoProxy
public class JavaConfig{
}

​ ⑤调用

public class Main{
	public static void main(String[] args){
	//获取容器
	AnnotationConfigApplicationContext ctx=new AnnotationConfigApplicationContext(JavaConfig.class);
    //获取Bean
	MyCalculator mycalculator = ctx.getBean(MyCalculator.class)//这里写实现类可能会找不到,写接口就行
    mycalculator.add(3,4);
	}
}
③定义增强(通知、Advice)的优化:

​ 一个一个配置不方便统一修改

解决:1.用一个方法定义切点:
@Component
@Aspect //表示这是一个切面
public class LogAspect{
    @Pointcut("@annotation(Action)")
    public void pointcut(){
        //一个空的方法,后续要改的时候只改这个方法即可
    }
    @Before(value="pointcut()")//这里写上面的方法名
    public viod before(JoinPoint joinPoint){
       //略
    }
}    
2.非侵入式优化:
@Component
@Aspect //表示这是一个切面
public class LogAspect{
    @Pointcut("execution(返回值类型 包名.某个类.某个方法(参数类型))")
    public void pointcut(){
        //一个空的方法,后续要改的时候只改这个方法即可
    }
    @Before(value="pointcut()")//这里写上面的方法名
    public viod before(JoinPoint joinPoint){
       //略
    }
}    

注意:

​ 返回值类型、某个类、某个方法可以用通配符 * ,代表任意/所有

​ 参数类型可以用 … (两个点)表示任意个数、任意类型的参数

xml配置使用时:

​ 基本与Java配置相同,区别在于

​ ①LogAspect文件中不必写注解,如@Before(value=“@annotation(xxx.xxx.xxx.Action)”)…,而是在xml文件中配置

<bean class="xxx.LogAspect" name="logAspect"/>
<bean class="xxx.MyxxxImpl" name="myxxx"/>
<aop:config>
    <aop:pointcut id="pointcut" expression="execution(返回值类型 包名.某个类.某个方法(参数类型))"/>
    <aop:aspect ref="logAspect">
        <aop:before method="before" pointcut="这里可以自定义,用-ref就是引用上面的"/>
        <aop:after method="after" pointcut-ref="pointcut"/>
        <aop:after-returning method="returning" pointcut-ref="pointcut" returning="r"/>
        <aop:afte-throwing method="throwing" pointcut-ref="pointcut" throwing="e"/>
        <aop:around method="around" pointcut-ref="pointcut"/>
    <aop:aspect/>
<aop:config>

​ ②调用时加载ClassPathXmlApplicationContext->getBean->用方法

JDBCTemplate

利用aop思想封装的JDBC操作工具

使用步骤

​ 1.新建项目,添加依赖spring-jdbc、spring-context、mysql-connector-java

​ 2.准备数据库及对应的实体类

​ 3.准备一个Java配置类,在其中配置JDBCTemplate:提供DataSource和JDBCTemplate的Bean

@Configuration
public class JDBCConfig{
    @Bean
    DataSource dataSource(){
        //通过DriverMangerDataSource获取dataSource
        DriverMangerDataSource dataSource=new DriverMangerDataSource();
        //设置dataSource的内容
        dataSource.setDriverClassName("com.mysql.cj.jdbc".Driver);
        dataSource.setUrl("jdbc:mysql://localhost:3306/database?useUnicode=true&amp;characterEncoding=UTF8");
        dataSource.setUsername("root");
        dataSource.setPassword("root");
        return dataSource;
    }
    @Bean
    JdbcTemplate jdbcTemplate(){
        return new JdbcTemplate(dataSource())
    }
}

​ 4.调用

​ AnnotationConfigApplicationContext获取容器ctx、getBean获得jdbcTemplate

​ 增删改使用jdbcTemplate.update(“sql语句”,“参数1”,"“参数2”…),查用query,如query(“sql语句”,new RowMapper())、query(“sql语句”,new BeanPropertyRowMapper(User.class))、quertForList

​ 定制需求可以用jdbcTemplate.update(预状态通道)

如果用xml配置,则上述3改为在xml文件中写

<bean class="xxx.DriverManagerDataSource" id="dataSource">
    <property name="driverClassName" value="xxx"/>
    <!--设置url、用户名、密码 略-->
<bean/>
<bean class="xxx.JdbcTemplate" id="jdbcTemplate">
    <property name="dataSource" ref="dataSource"/>
<bean/>

在4中获取容器用ClassPathXmlApplicationContext

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值