Spring5

IoC

控制反转Ioc(Inversion of Control),是一种设计思想,DI(依赖注入)是实现Ioc的一种方法。

控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式。在Spring中实现控制反转的是IoC容器,其实现方法是依赖注入(Dependency Injection,DI)。

IoC创建对象方式

使用无参构造创建对象

实体类

package com.kuang.pojo;

public class User {
    private String name;
    
    public String getName() {
        return name;
    }
    
    public void setName(String name) {
        this.name = name;
    }
}

ApplicationContext.xml

在resource目录下

<?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">
    
    <!-- 使用Spring来创建对象,在Spring,这些都称Bean -->
    <bean id="user" class="com.kuang.pojo.User">
        //这个是利用实体类的set方法来进行注入的
        //这个property作用是提前设置实体类的字段值,也可以不写property
        <property name="name" value="pakhm" />
    </bean>
</beans>

程序入口

public class MyTest{
    public static void main(String[] args){
        
        //获取Spring的上下文对象
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("ApplicationContext.xml");
        
        //我们的对象现在都在Spring中的管理了,我们要使用,直接去里面取出来就可以
        Hello hello =(Hello)applicationContext.getBean("hello");
        System.out.println(hello);
    }
}

使用有参构造创建对象

实体类

package com.kuang.pojo;

public class User {
    private String name;
    
    public User(String name){
        this.name=name;
    }
    
    public String getName() {
        return name;
    }
    
    public void setName(String name) {
        this.name = name;
    }
}

程序入口

public class MyTest{
    public static void main(String[] args){
        
        //获取Spring的上下文对象
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("ApplicationContext.xml");
        
        //我们的对象现在都在Spring中的管理了,我们要使用,直接去里面取出来就可以
        Hello hello =(Hello)applicationContext.getBean("hello");
        System.out.println(hello);
    }
}

三种方式

使用下标

在resource目录下ApplicationContext.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">
    
    <!-- 使用Spring来创建对象,在Spring,这些都称Bean -->
    <bean id="user" class="com.kuang.pojo.User">
        <construtor-arg index="0" value="pakhm1" />
    </bean>
</beans>

使用类型

在resource目录下ApplicationContext.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">
    
    <!-- 使用Spring来创建对象,在Spring,这些都称Bean -->
    <bean id="user" class="com.kuang.pojo.User">
        <construtor-arg type="java.lang.String" value="pakhm2" />
    </bean>
</beans>

缺陷:如果实体类有多个相同类型的字段,那么就不能用这种方式

使用字段名

在resource目录下ApplicationContext.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">
    
    <!-- 使用Spring来创建对象,在Spring,这些都称Bean -->
    <bean id="user" class="com.kuang.pojo.User">
        <construtor-arg name="name" value="pakhm3" />
    </bean>
</beans>

总结

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

ApplicationContext.xml配置说明

beans

里面可以放多个bean

description

描述

alias

<alias name="user" alias="myUser"/>

name:bean的id

alias:别名

bean

注册配置bean

<bean id="userT" class="com.kuang.pojo.userT" name="user2 user3,user4;user5" scope="singleton">
    ...
</bean>

id:bean的唯一标识符

class:对象的全限定名称

name:别名,别名可以取多个,可以用空格、逗号、";"来取多个值

scope:bean的作用域,默认值是singleton

import

可以将多个配置文件导入合并为一

<import resource="xxx.xml" />

如果多个配置文件有内容相同的部分,那么会合并

DI依赖注入

(有参)构造器注入

上面 IoC创建对象方式 中的 使用有参构造创建对象就是构造器注入

set方式注入

实体类

@Data
public class Student {
    private String name;
    private Address address;
    private String[] books;
    private List<String> hobbies;
    private Map<String,String> card;
    private Set<String> games;
    private String wife;
    private Properties info;
}

ApplicationContext.xml

在resource目录下

<?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="myAddress" class="com.kuang.pojo.Address" />
    
    <bean id="student" class="com.kuang.pojo.Student">
        
        //1.注入基本数据类型
        <property name="name" value="pakhm" />
        
        //2.注入我自己创建的类
        <property name="address" ref="myAddress" />
        
        //3.注入数组类型
        <property name="books">
            <array>
                <value>西游记</value>
                <value>三国演义</value>
                <value>水浒传</value>
            </array>
        </property>
        
        //4.注入List类型
        <property name="hobbies">
            <array>
                <value>听歌</value>
                <value>玩游戏</value>
            </array>
        </property>
        
        //5.注入Map类型
        <property name="card"> 
            <map>
                <entry key="身份证" value="123" />
                <entry key="身份证" value="456" />
            </map>
        </property>
        
        //5.注入Set类型
        <property name="games">
            <set>
                <value>LOL</value>
                <value>DNF</value>
            </set>
        </property>
        
        //6.注入null
        <property name="wife">
            <null/>
        </property>
        
        //7.注入Properties类型
        <property name="info">
            <props>
                <prop key="年龄">123</prop>
                <prop key="身高">456</prop>
            </props>
        </property>
    </bean>
</beans>

p命名空间注入

相当于set注入的简化版

<bean name="jane" class="com.example.Person">
    <property name="name" value="Jane Doe"/>
</bean>

<bean name="john-classic" class="com.example.Person">
    <property name="name" value="Jane Doe"/>
    <property name="spouse" ref="jane"/>
</bean>
//相当于
<bean name="john-modern" class="com.example.Person" p:name="Jane Doe" p:spouse-ref="jane" />

c命名空间注入

相当于(有参)构造器注入的简化版

<bean name="beanTwo" class="x.y.ThingTwo"/>
<bean name="beanThree" class="x.y.ThingThree"/>

<bean id="beanOne" class="x.y.ThingOne">
    <constructor-arg name="thingTwo" ref="beanTwo"/>
    <constructor-arg name="thingThree" ref="beanThree"/>
    <constructor-arg name="email" value="xx@qq.com"/>
</bean>
//相当于
<bean id="beanOne" class="x.y.ThingOne" c:thingTwo-ref:"beanTwo" c:thingThree-ref:"beanThree" c:email="xx@qq.com"/>

bean的作用域

singleton(单列模式)

<bean id="user2" class="com.kuang.pojo.User" c:age="19" c:name="pakhm" scope="singleton"/>

Spring默认机制,每次获取这个对象的时候,拿到的都是同一个对象,内存地址一样。

prototype(原型模式)

<bean id="user2" class="com.kuang.pojo.User" c:age="19" c:name="pakhm" scope="prototype"/>

每次获取这个对象的时候,拿到的都是不同的对象,内存地址不一样。

其他

request,session,application,websocket在web开发中使用到。

装配bean的方式

xml中显式配置

上面的DI依赖注入就是xml中显式配置

java中显式配置

配置类

//这个也会Spring容器托管,注册到容器中,因为他本来就是一个@Component
//@Configuration代表这是一个配置类,就和我们之前看的ApplicationContext.xml
@Configuration
@ComponentScan("com.kuang.pojo")
@Import(KuangConfig2.class)
public class KuangConfig {
    
    //注册一个bean,就相当于我们之前写的一个bean标签
    //这个方法的名字,就相当于bean标签中的id属性
    //这个方法的返回值,就相当于bean标签中的class属性
    @Bean
    public User user(){
        return new User();
    }
}

程序入口

public class MyTest{
    public static void main(String[] args){
        //如果完全使用了配置类方式去做,我们就只能通过AnnotationConfig上下文来获取容器,通过配置类的class对象加载
        ApplicationContext context = new AnnotationConfigApplicationContext(KuangConfig.class);
        User getUser=(User) context.getBean("user");
    }
}

隐式的自动装配

实体类

@Data
public class Dog{
    public void shout(){
        System.out.println("wang~")
    }
}
@Data
public class Cat{
    public void shout(){
        System.out.println("wang~")
    }
}
@Data
public class People{
    private Cat cat;
    private Dog dog;
    private String name;
}

ApplicationContext.xml

xml中显式配置

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

<bean id="people" class="com.kuang.pojo.People">
    <property name="name" value="pakhm"/>
    
    <property name="cat" ref="cat"/>
    <property name="dog" ref="dog"/>
</bean>

byName

会自动在容器上下文中查找,和自己对象set方法后面的值对应的beanId

要保证所有bean的id唯一,并且这个bean需要和自动注入的属性的set方法的值一致

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

<bean id="people" class="com.kuang.pojo.People" autowire="byName">
    <property name="name" value="pakhm"/>
</bean>

byType

会自动在容器上下文中查找,和自己对象属性类型相同的bean

要保证所有bean的class唯一,并且这个bean需要和自动注入的属性的类型一致

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

<bean id="people" class="com.kuang.pojo.People" />

注解

//开启注解支持
<context:annotation-config/>

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

<bean id="people" class="com.kuang.pojo.People" />

实体类中,在属性上、或者set方法上使用注解

使用@Autowired,我们可以不用编写Set方法了,前提是你这个自动装配的属性在IOC(Spring)容器中存在,且符合名字byName

@Autowired有一个参数required,默认值是true,如果这个值为false,说明这个属性可以为null,否则不允许为空

@Data
public class People{
    @Autowired
    private Cat cat;
    @Autowired(required = false)
    private Dog dog;
    private String name;
}

@Autowired找bean的时候先用byType,如果找不到的话再用byName。如果这两个操作还不能找到bean的话我们可以使用@Qualifier来指定我们想要的bean,@Qualifier里面写beanId

@Data
public class People{
    @Autowired
    @Qualifier(value="xxx")
    private Cat cat;
    @Autowired
    private Dog dog;
    private String name;
}

@Resource注解也可以用来自动装配

@Resource找bean的时候先用byName,如果找不到的话再用byType。如果这两个操作还不能找到bean的话我们可以给@Resource里面写指定的beanId

@Data
public class People{
    @Resource
    private Cat cat;
    @Resource(name="xxx")
    private Dog dog;
    private String name;
}

Spring注解开发

ApplicationContext.xml

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

实体类

//这个注解等价于 <bean id="user" class="com.kuang.pojo.User" />
@Component
//设置bean的作用域
@Scope("prototype")
@Data
public class User{
    
    //这个注解相当于 <property name="name" value="pakhm"/>,这个注解也可以放在set方法上面
    @Value("pakhm")
    public String name;
}

Component衍生的注解

功能跟@Component一样,都是将某个类注册到Spring中,装配Bean

@Repository:用在dao层

@Service:用在service层

@Controller:用在controller层

AOP

环境准备

Spring实现AOP需要导入一个依赖包

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.4</version>
</dependency>

使用原生Spring API接口方式

MethodBeforeAdvice

方法执行之前

public class Log implements MethodBeforeAdvice {
    
    //method:要执行的目标对象的方法
    //args:参数
    //target:目标对象
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println(target.getClass().getName()+"的"+method.getName()+"被执行了")
    }
}

AfterReturningAdvice

方法执行之后

public class AfterLog implements AfterReturningAdvice {
    
    //returnValue:返回值
    public void afterReturning(Object returnValue,Method method,Object[] args,Object target){
        System.out.println("执行了"+method.getName()+"方法,返回结果为:"+returnValue)
    }
}

ApplicationContext.xml

<!-- 注册bean -->
<bean id="userService" class="com.kuang.service.UserServiceImpl" />
<bean id="log" class="com.kuang.log.Log" />
<bean id="afterLog" class="com.kuang.log.AfterLog" />

<!-- 配置AOP -->
<aop:config>
    
    <!-- 切入点 -->
    <aop:pointcut id="pointcut" expression="execution(* com.kuang.servie.UserServiceImpl.*(..))"></aop:pointcut>
    
    <!-- 执行环绕增加 -->
    <aop:advisor advice-ref="log" pointcut-ref="pointcut"></aop:pointcut>
    <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"></aop:pointcut>
</aop:config>
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,001评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,210评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,874评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,001评论 1 291
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,022评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,005评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,929评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,742评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,193评论 1 309
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,427评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,583评论 1 346
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,305评论 5 342
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,911评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,564评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,731评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,581评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,478评论 2 352

推荐阅读更多精彩内容