spring太强了!两万多字干货 超详细讲解(二)

简介: spring太强了!两万多字干货 超详细讲解

3.2 根据属性名注入(推荐)


实体类User

该实体类有各种各样的类型,我们尝试对这些复杂数据类型进行注入

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private String name;
    private Address address;
    private String[] books;
    private List<String> hobbys;
    private Map<String,String> card;
    private Set<String> games;
    private Properties info;
    private String girlFriend;
}


XML注入

一共八种数据类型,分别加以注入

<!--propertyNameAddress  根据属性名注入的address-->
<!--singleton 单例模式 prototype原型模式-->
<bean id="address" class="zwz.pojo.Address" scope="singleton">
    <property name="address" value="浙江宁波"/>
</bean>
<bean id="user" class="zwz.pojo.User">
    <!--        第一种 普通值注入-->
    <property name="name" value="ZWZ"></property>
    <!--        第二种 Bean注入-->
    <property name="address" ref="address"></property>
    <!--        第三种 数组-->
    <property name="books">
        <array>
            <value>Java程序设计</value>
            <value>JavaScript程序设计</value>
            <value>Python程序设计</value>
        </array>
    </property>
    <!--        第四种 List-->
    <property name="hobbys">
        <list>
            <value>敲代码</value>
            <value>听歌</value>
            <value>看小说</value>
        </list>
    </property>
    <!--        第五种 Map-->
    <property name="card">
        <map>
            <entry key="card01" value="卡片1"></entry>
            <entry key="card02" value="卡片2"></entry>
            <entry key="card03" value="卡片3"></entry>
        </map>
    </property>
    <!--        第六种 Set-->
    <property name="games">
        <set>
            <value>QQ飞车手游</value>
            <value>DNF</value>
            <value>敲代码</value>
        </set>
    </property>
    <!--        第七种 空值-->
    <property name="girlFriend">
        <null></null>
    </property>
    <!--        第八种 配置-->
    <property name="info">
        <props>
            <prop key="id">0413170337</prop>
            <prop key="tel">17857054388</prop>
        </props>
    </property>
</bean>


测试

@Test
public void testPropertyName() {
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    User user = (User) context.getBean("user");
    System.out.println(user);
}

可以看出,八种数据类型,都已经成功注入到对象中

Student{
name='ZWZ'
, address=Address(address=浙江宁波)
, books=[Java程序设计, JavaScript程序设计, Python程序设计]
, hobbys=[敲代码, 听歌, 看小说]
, card={card01=卡片1, card02=卡片2, card03=卡片3}
, games=[QQ飞车手游, DNF, 敲代码]
, info={tel=17857054388, id=0413170337}
, girlFriend='null'}
Process finished with exit code 0


3.3 根据构造器下标注入


@AllArgsConstructor 注解在之间提到过,是生成全部参数的构造方法

我们可以通过构造器的参数,实现值注入

比如对于构造器0号下标的bookName,注入Java程序设计…


实体类Book

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Book {
    private String bookName;
    private int pageNum;
}


XML注入

<bean id="bookIndex" class="zwz.pojo.Book">
    <constructor-arg index="0" value="Java程序设计"/>
    <constructor-arg index="1" value="66"/>
</bean>


测试

@Test
    public void testConstructorIndex() {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        Book book = (Book) context.getBean("bookIndex");
        System.out.println(book);
    }


Book(bookName=Java程序设计, pageNum=66)
Process finished with exit code 0


3.4 根据构造器数据类型注入

@AllArgsConstructor 注解在之间提到过,是生成全部参数的构造方法

我们可以通过构造器的参数类型,实现值注入

比如对于构造器的String类型变量bookName,注入Java程序设计…

当然构造器**不同参数的数据类型必须不一致,否则会出错**,所以这个注入方式说实话没什么用…


### 实体类Book

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Book {
    private String bookName;
    private int pageNum;
}


XML注入

<bean id="bookType" class="zwz.pojo.Book">
    <constructor-arg type="java.lang.String" value="Java程序设计"/>
    <constructor-arg type="int" value="66"/>
</bean>


测试

@Test
public void testConstructorType() {
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    Book book = (Book) context.getBean("bookType");
    System.out.println(book);
}


Book(bookName=Java程序设计, pageNum=66)
Process finished with exit code 0


3.5 C / P 命名空间注入

c命名空间注入或者p命名空间注入,分别利用变量名称和构造器下标进行值注入,和之前的没有本质性的区别

XML属性名注入、Java注解最为常用,而C/P命名空间注入一般不会去使用…


实体类Book

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Book {
    private String bookName;
    private int pageNum;
}


XML注入

<bean id="cBook" class="zwz.pojo.Book" c:_0="Java程序设计" c:_1="66"/>
<bean id="pBook" class="zwz.pojo.Book" p:bookName="Java程序设计" p:pageNum="66"/>


测试

@Test
public void testC() {
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    Book book = (Book) context.getBean("cBook");
    System.out.println(book);
}
@Test
public void testP() {
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    Book book = (Book) context.getBean("pBook");
    System.out.println(book);
}

输出相同

Book(bookName=Java程序设计, pageNum=66)
Process finished with exit code 0


3.6 单例/原型模式


XML配置


singleton 为单例模式,从容器中多次获取bean,bean相同

prototype为原型模式,从容器中多次获取bean,bean不同

<bean id="singletonBook" class="zwz.pojo.Book" scope="singleton">
    <property name="bookName" value="Java程序设计"/>
    <property name="pageNum" value="66"/>
</bean>
<bean id="prototypeBook" class="zwz.pojo.Book" scope="prototype">
    <property name="bookName" value="Java程序设计"/>
    <property name="pageNum" value="66"/>
</bean>


测试

@Test
public void testScope(){
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    Book book1 = (Book) context.getBean("singletonBook");
    Book book2 = (Book) context.getBean("singletonBook");
    System.out.println("singletonBook: " + (book1 == book2));
    Book book3 = (Book) context.getBean("prototypeBook");
    Book book4 = (Book) context.getBean("prototypeBook");
    System.out.println("prototypeBook: " + (book3 == book4));
}


``` singletonBook: true prototypeBook: false ```



3.7 自动装配


自动装配的意思是,假设有两个实体Bean A、B

如果A中包含B,且B已经配置在容器中,那么A可以通过自动装配,将B自动装配注入

当然自动装配只对引用变量生效,对于int、String不支持


实体类BookUser

定义一个包含Book的实体类BookUser

@Data
@AllArgsConstructor
@NoArgsConstructor
public class BookUser {
    Book book;
}


### XML配置

<bean id="book" class="zwz.pojo.Book">
    <property name="bookName" value="自动装配的BookName"/>
    <property name="pageNum" value="66"/>
</bean>
<!--
- byName 要求所有的bean 的 id 唯一,并且set方法要规范
- byType 要求所有的bean 的 class 唯一,并且set方法要规范
-->
<bean id="bookUser" class="zwz.pojo.BookUser" autowire="byName"/>


测试

@Test
public void testAutowire(){
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    BookUser bookUser = (BookUser) context.getBean("bookUser");
    System.out.println(bookUser);
}


BookUser(book=Book(bookName=自动装配的BookName, pageNum=66))
Process finished with exit code 0


3.8 Java注解开发(推荐)


实体类House

@Data
@AllArgsConstructor
@NoArgsConstructor
public class House {
    @Value("幸福之家")
    private String houseName;
    @Value("99")
    private String houseSize;
}


XML配置

<!--使用注解必须开启注解支持-->
<context:annotation-config/>
<bean id="house" class="zwz.pojo.House"/>


测试

@Test
public void testJava(){
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    House house= (House) context.getBean("house");
    System.out.println(house);
}


House(houseName=幸福之家, houseSize=99)
Process finished with exit code 0


3.9 spring常用注解


  • @Autowired 直接在变量上使用,也可以在set方法上使用,需要符合名字byName原则 【 最常用!!!】
  • @Nullable 直接在变量上使用,表示这个变量允许为空
  • @Qualifier(value=“xxx”) 直接在变量上使用,指定bean的id
  • @Resource 或者 @Resource(value=“xxx”) ,同 @Autowired 和 @Qualifier(value=“xxx”)
  • @Value(“xxx”),在实体类的某个变量注入值,也可放在set方法上
  • @Component,在spring中注册装配bean,通用
  • @Repository,在spring中注册装配bean,一般放在Dao层上
  • @Service,在spring中注册装配bean,一般放在Service层上
  • @Controller,在spring中注册装配bean,一般放在Controller层上
  • @Scope(“prototype/singleton”),配置实体类的单例/原型模式
  • @Configuration,Java配置类的注解


四、 AOP 面向切面编程


4.1 静态代理


  • 抽象角色:接口/抽象类,代表某种需求【租房】
  • 真实角色:被代理的角色【房东】
  • 代理角色:代理真实角色【租房中介】
  • 客户:访问代理对象【租房的人】

假设场景:XX通信公司在高校内售卖校园卡



【抽象角色】就是卖卡这个需求

// 卖校园卡
public interface SellingCard {
    void sellingCard();
}


【真实角色】要卖卡的公司

public class Company implements SellingCard{
    @Override
    public void sellingCard() {
        System.out.println("XX公司要卖校园卡!");
    }
}


【代理角色】高校内的各级代理,卖卡之余,还提供各种服务

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Proxy implements SellingCard{
    private Company company;
    @Override
    public void sellingCard() {
        learnCard();
        company.sellingCard();
        contract();
        collectMoney();
    }
    // 了解校园卡功能
    public void learnCard(){
        System.out.println("校园卡代理带你了解校园卡费用");
    }
    // 收取卖卡推销费用
    public void collectMoney(){
        System.out.println("收取卖卡推销费用");
    }
    // 代理指导你签电子合同
    public void contract(){
        System.out.println("代理指导你签电子合同");
    }
}


【客户】买卡的学生,访问代理角色,buyCard()为直接找公司购卡,buyCardProxy()为找代理购卡

public class Student {
    @Test
    public void buyCardProxy(){
        // XX校园卡公司,要卖校园卡
        Company company = new Company();
        //代理中介,帮公司卖卡,收取一定费用
        Proxy proxy = new Proxy(company);
        // 客户不用面对公司,直接找代理买卡即可
        proxy.sellingCard();
    }
    @Test
    public void buyCard(){
        Company company = new Company();
        company.sellingCard();
    }
}


校园卡代理带你了解校园卡费用
XX公司要卖校园卡!
代理指导你签电子合同
收取卖卡推销费用
Process finished with exit code 0


代理模式的优点:

  • 让真实角色的需求【房东卖房】更加简单,不用去关注一些其他手续【客户看房,签合同等】
  • 其他手续交给了代理,实现业务分工
  • 其他手续需求扩展时,方便集中管理


代理模式的缺点:

  • 一个真实角色【房东】,就会产生一个代理角色【租房中介】,使得代码量会翻倍


4.2 动态代理


和静态代理一样,也是卖卡这个场景


【需求】卖卡(同静态代理一致)

// 卖校园卡
public interface SellingCard {
    void sellingCard();
}


【真实角色】要卖卡的公司(同静态代理一致)

public class Company implements SellingCard {
    @Override
    public void sellingCard() {
        System.out.println("XX公司要卖校园卡!");
    }
}


【代理角色】动态代理

@Data
@AllArgsConstructor
@NoArgsConstructor
public class ProxyAction implements InvocationHandler {
    // 被代理的接口
    private SellingCard sellingCard;
    public Object getProxy(){
        return  Proxy.newProxyInstance(this.getClass().getClassLoader(),
                sellingCard.getClass().getInterfaces(),this);
    }
    // 处理代理实例,并返回结果
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        learnCard();
        // 动态代理  反射机制实现
        Object result = method.invoke(sellingCard, args);
        collectMoney();
        contract();
        return result;
    }
    // 了解校园卡功能
    public void learnCard(){
        System.out.println("校园卡代理带你了解校园卡费用");
    }
    // 收取卖卡推销费用
    public void collectMoney(){
        System.out.println("收取卖卡推销费用");
    }
    // 代理指导你签电子合同
    public void contract(){
        System.out.println("代理指导你签电子合同");
    }
}


【客户】买卡的学生

public class Student {
    @Test
    public void testProxyAction(){
        // 真实角色
        Company company = new Company();
        // 代理角色
        ProxyAction pa = new ProxyAction();
        // 通过调用程序处理调用的接口对象 | 就是让代理实现 SellingCard 卖卡的接口
        pa.setSellingCard(company);
        // 获得代理类 | proxy 就是动态生成的
        SellingCard proxy = (SellingCard) pa.getProxy();
        proxy.sellingCard();
    }
}


相关文章
|
安全 Java 测试技术
Github标星98k,Alibaba最新发布的Spring Boot项目实战文档!太强了
前言 又到了一年一度的备战秋招的时间,虽然这两年因为经济环境不太好,互联网行业的各大厂都再裁员,但是今年的秋招经济形势正在复苏,我特地拜托阿里的朋友将这份Spring Boot项目实战开发文档分享出来。 本文档涵盖Spring Boot企业级项目开发的各方面知识,重点介绍Maven项目的搭建、Jersey Restful风格、Postman测试接口、Swagger2可视化文档、Lombok优雅编码、Redis缓存、Security安全机制、Web Service服务、WebSocke t通信、性能测试、集成测试、Jeecg Boot快速开发框架、使用Docker进行项目部署、使
|
安全 Java 测试技术
Github标星98k,Alibaba最新发布的Spring Boot项目实战文档!太强了
前言 又到了一年一度的备战秋招的时间,虽然这两年因为经济环境不太好,互联网行业的各大厂都再裁员,但是今年的秋招经济形势正在复苏,我特地拜托阿里的朋友将这份Spring Boot项目实战开发文档分享出来。 本文档涵盖Spring Boot企业级项目开发的各方面知识,重点介绍Maven项目的搭建、Jersey Restful风格、Postman测试接口、Swagger2可视化文档、Lombok优雅编码、Redis缓存、Security安全机制、Web Service服务、WebSocke t通信、性能测试、集成测试、Jeecg Boot快速开发框架、使用Docker进行项目部署、使用sp
134 0
|
Java 数据库连接 API
spring太强了!两万多字干货 超详细讲解(三)
spring太强了!两万多字干货 超详细讲解
|
XML Java Maven
spring太强了!两万多字干货 超详细讲解(一)
spring太强了!两万多字干货 超详细讲解
|
消息中间件 分布式计算 数据可视化
Spring Boot + 规则引擎 URule,太强了!
Spring Boot + 规则引擎 URule,太强了!
|
Java Docker 容器
Docker + Spring Boot + FastDFS 搭建一套分布式文件服务器,太强了
首先说一下从零开始自己去搭一个fastdfs挺麻烦,后来看到有人把做好的 docker 镜像传出来了,那搭建起来就很容易了
212 0
Docker + Spring Boot + FastDFS 搭建一套分布式文件服务器,太强了
|
2月前
|
SQL 监控 druid
springboot-druid数据源的配置方式及配置后台监控-自定义和导入stater(推荐-简单方便使用)两种方式配置druid数据源
这篇文章介绍了如何在Spring Boot项目中配置和监控Druid数据源,包括自定义配置和使用Spring Boot Starter两种方法。
|
1月前
|
人工智能 自然语言处理 前端开发
SpringBoot + 通义千问 + 自定义React组件:支持EventStream数据解析的技术实践
【10月更文挑战第7天】在现代Web开发中,集成多种技术栈以实现复杂的功能需求已成为常态。本文将详细介绍如何使用SpringBoot作为后端框架,结合阿里巴巴的通义千问(一个强大的自然语言处理服务),并通过自定义React组件来支持服务器发送事件(SSE, Server-Sent Events)的EventStream数据解析。这一组合不仅能够实现高效的实时通信,还能利用AI技术提升用户体验。
162 2
|
8天前
|
缓存 IDE Java
SpringBoot入门(7)- 配置热部署devtools工具
SpringBoot入门(7)- 配置热部署devtools工具
19 2
 SpringBoot入门(7)- 配置热部署devtools工具
|
4天前
|
存储 运维 安全
Spring运维之boot项目多环境(yaml 多文件 proerties)及分组管理与开发控制
通过以上措施,可以保证Spring Boot项目的配置管理在专业水准上,并且易于维护和管理,符合搜索引擎收录标准。
15 2