Spring

注解(Annotation)和反射( Reflection)

注解(Annotation)

  • 注解(Annotation) 的作用
    • 不是程序本身,可以对程序作出解释(这一点和注释没什么区别)
    • 可以被其它程序(比如:编译器等)读取
  • Annotation 的格式
    • 注解是以 “@注释名” 在代码中存在的,还可以添加一些参数值,例如: @SuppressWarnings(value=“unchecked”)
  • Annotation 在哪里使用?
    • 可以附加在 package,class,method,field 等上面,相当于给他们添加了额外的辅助信息,我们可以通过反射机制编程实现对这些元数据的访问

元注解

  • 元注解的作用就是负责注解其它注解,Java 定义了 4 个标准的 meta-annotation 类型,它们被用来提供对其它注解类型做说明
  • 这些类型和它们所支持的类在 java.lang.annotation 包中可以找到(@Target,@Retention,@Documented,@Inherited)

@Target

用于描述注解的使用范围(即:被描述的注解可以用在什么地方)

如:我们自定义一个注解

@Retention

表示需要在什么级别保存该注释信息,用于描述注解的生命周期(SOURCE < CLASS < RUNTIME

在这里插入图片描述

@Documented

说明该注解将被包含在 javadoc 中

在这里插入图片描述

@Inherited

说明子类可以继承父类中的该注解

在这里插入图片描述

 反射( Reflection)

 Reflection(反射)是 Java 被视为动态语言的关键,反射机制允许程序在执行期借助于 Reflection API 取得任何类的内部信息,并能直接操作任意对象的内部属性以及方法

Class c = Class.forName("java.lang.String");

加载完类之后,在堆内存的方法区中就产生了一个 Class 类型的对象(一个类只有一个 Class 对象),这个对象就包含了完整类的类的结构信息。我们可以通过对这个对象看到的类的结构。这个对象就像一面镜子,通过这个镜子看到类的结构,所以,我们形象地称之为:反射

  • 正常方式:引入需要的 “ 包类 ” 名称 ——> 通过 new 实例化 ——> 取得实例化对象
  • 反射方式:实例化对象 ——> getClass() 方法 ——> 得到完整的 “包类” 名称

Java 反射机制提供的功能

  • 在运行时判断任意一个对象所属的类
  • 在运行时构造任意一个类的对象
  • 在运行时判断任意一个类所具有的成员变量和方法
  • 在运行时获取泛型信息
  • 在运行时调用任意一个对象的成员变量和方法
  • 在运行时处理注解
  • 生成动态代理

Java 反射优点和缺点

优点: 可以实现动态创建对象和编译,体现出很大的灵活性

缺点: 对性能有影响。使用反射基本上是一种解释操作,我们可以告诉 JVM,我们希望做什么并且它满足我们什么要求,这类操作总是慢于直接执行相同的操作

反射相关的主要 API

  • java.lang.Class 代表一个类
  • java.lang.reflect.Method 代表类的方法
  • java.lang.reflect.Field 代表类的成员变量
  • java.lang.reflect.Constructor 代表类的构造器

1.Spring

1.1 简介

Spring理念:使现有的技术更加容易使用,本身是一个大杂烩。

SSM:SpringMVC+Spring+Mybatis

官网地址:Spring | Home

Spring下载地址:JFrog

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

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

1.2 优点

1.Spring是一个开源的免费框架(容器)

2.Spring是一个轻量级的、非入侵式的框架

3.控制反转(IOC),面向切面编程(AQP)

4.支持事务的处理,对框架整合的支持

总结:Spring是一个轻量级的控制反转(IOC)和面向切面编程(AQP)的框架!

1.3 组成

 1.4 拓展

在Spring官网有这个介绍:现代化java的开发!说白了就是基于Spring的开发。

 SpringBoot:

         一个快速开发的脚手架。

        基于SpringBoot可以快速开发单个微服务。

        约定大于配置!

SpringCloud:

        SpringCloud是基于SpringBoot实现的

学习SpringBoot的前提是需要完全掌握Spring及SpringMaven

弊端:“配置地狱”

1.5 MAVEN

下载安装MAVEN:Maven – Download Apache Maven

配置环境:

M2_HOME:  MAVEN目录下的bin目录

MAVEN_HOME :MAVEN目录

在系统的path中配置:%MAVEN_HOME%\bin

 配置成功

1.5.1 修改配置文件(阿里云镜像)

镜像:mirrors

        作用:加速下载

建议使用国内阿里云镜像

<mirror>
    <id>nexus-aliyun</id>
    <mirrorOf>*,!jeecg,!jeecg-snapshots</mirrorOf>
    <name>Nexus aliyun</name>
    <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
</mirror>

1.5.2本地仓库

在本地的仓库,远程仓库

建立一个本地仓库:localRepository

 <localRepository>D:\浏览器下载\apache-maven-3.8.4-bin\apache-maven-3.8.4\maven-repo</localRepository>

1.5.3 在idea中使用maven

1.创建一个新的mavenweb 项目(使用模板)

标记文件夹功能

 2.创建一个新的mavenweb 项目(不使用模板)

3.maven最核心的就是pom.xml文件

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>org.example</groupId>
  <artifactId>maven</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>war</packaging>

  <name>maven Maven Webapp</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.example.com</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.7</maven.compiler.source>
    <maven.compiler.target>1.7</maven.compiler.target>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

  <build>
    <finalName>maven</finalName>
    <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
      <plugins>
        <plugin>
          <artifactId>maven-clean-plugin</artifactId>
          <version>3.1.0</version>
        </plugin>
        <!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
        <plugin>
          <artifactId>maven-resources-plugin</artifactId>
          <version>3.0.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>3.8.0</version>
        </plugin>
        <plugin>
          <artifactId>maven-surefire-plugin</artifactId>
          <version>2.22.1</version>
        </plugin>
        <plugin>
          <artifactId>maven-war-plugin</artifactId>
          <version>3.2.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-install-plugin</artifactId>
          <version>2.5.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-deploy-plugin</artifactId>
          <version>2.8.2</version>
        </plugin>
      </plugins>
    </pluginManagement>
  </build>
</project>

2. IOC理论推导

对于Spring这样的框架,(View\Web)表示层调用控制层(Controller),控制层调用业务层(Service),业务层调用数据访问层(Dao)。
具体起来,Dao的作用是封装对数据库的访问:增删改查,不涉及业务逻辑,只是达到按某个条件获得指定数据的要求;
而Service,则是专注业务逻辑,对于其中需要的数据库操作,都通过Dao去实现;

1.UserDao接口

2.UserDaoImpl实现类

3.UserService业务接口

4.UserServiceImpl业务实现类

在我们之前的业务中,用户的需求很可能会影响我们原来的代码,我们需要根据用户的需求去修改代码。如果程序量十分大,修改一次的成本代价十分昂贵!

我们使用一个Set接口实现:

private UserDao userDao ;
    //利用set进行动态实现值的注入
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

之前程序是主动创建对象,控制权在程序员手上。

  private UserDao userDao = new UserDaoMysqlImpl() ;

使用set注入后,程序不在具有主动性,而是变成了被动的接收对象!

 这种思想,从本质上解决了问题,我们程序员再也不用去管理对象的创建了!系统的耦合性大大降低~可以更加专注的在业务的实现上。这是IOC的原型        

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

3.Hello Spring

   Spring核心     XML配置文件网址:Core Technologies

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
        https://www.springframework.org/schema/beans/spring-beans.xsd">

   <bean id="mysqlImpl" class="com.zeng.dao.UserDaoMysqlImpl"/>
   <bean id="oracleImpl" class="com.zeng.dao.UserDaoOracleImpl"/>

   <bean id="UserServiceImpl" class="com.zeng.service.UserServiceImpl">
   <property name="userDao" ref="mysqlImpl"/>
   </bean>
   <!--
    ref:引用spring容器中创建好的对象
    value:具体的值,基本数据类型
    -->
</beans>
<?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:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util https://www.springframework.org/schema/util/spring-util.xsd">
    <!-- 使用Spring来创建对象,在Spring中这些都称为Bean
    类型  变量名  = new 类型();
    Hello hello = new Hello();

    id = 变量名;
    class = new的对象;
    property 相当于给对象中的一个属性设置一个值

    -->
    <bean id="hello" class="com.zeng.pojo.Hello" >
        <property name="str" value="Spring"/>
    </bean>
</beans>

控制:谁来控制对象的创建,传统应用程序的对象是有程序本身控制创建的,使用Spring后,对象是由Spring来创建。

反转:程序本身不创建对象,而变成被动的接收对象

依赖注入:就是利用set方法来进行注入的

IOC是一种编程思想,由主动的编程变成被动的接收。

到了现在,彻底不用与程序中改动了,要实现不同的操作,只需要在xml配置文件中进行修改。所谓的IOC,一句话总结就是:对象由Spring来创建、管理、装配!

4.IOC创建对象的方式

1.使用无参构造创建对象,默认!

2.假设我们使用有参构造创建对象。 

        (1)下标赋值

<!-- 有参构造第一种方法:下标赋值  -->  
<bean id="user" class="com.zeng.pojo.User">
       <constructor-arg index="0" value="胖胖说java"/>
    </bean>

        (2)通过类型创建

    <!-- 第二种有参构造方法:通过类型创建  不建议使用 -->
    <bean id="user" class="com.zeng.pojo.User">
        <constructor-arg type="java.lang.String" value="pagnpang"/>
    </bean>

        (3)直接通过参数名来设置

    <!--第三种有参构造方法:直接通过参数名来设置 -->
    <bean id="user" class="com.zeng.pojo.User">
        <constructor-arg name="name" value="屁屁"/>
    </bean>

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

5. Spring配置

5.1别名

    <!-- 别名,如果添加了别名,我们也可以通过别名获取这个对象 -->
    <alias name="user" alias="userNew"/>

5.2 Bean的配置

    <!--
    id: Bean的唯一标识符,也就是相当于对象名
    class: Bean对象所对应的全限定名:包名+类名
    name: 也是别名,而且name可以同时取多个别名
    -->
    <bean id="user" class="com.zeng.pojo.User2" name="user2,u2 u3">
    <property name="name" value="有点蒙"/>
    </bean>

5.3  import

import一般用于团队开发,它可以将多个配置文件导入合并为一个

假设一个项目中有多个人开发,这几个人复制不同的类的开发,不同的类需要注册在不同的bean中,我们可以利用import将所有人的bean.xml合并为一个总的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
        https://www.springframework.org/schema/beans/spring-beans.xsd">
    
    <import resource="beans.xml"/>
    <import resource="beans2.xml"/>
    <import resource="beans3.xml"/>

    </beans>

6、依赖注入(DI)

6.1 构造器注入

6.2 Set方式注入(重点)

依赖注入;set注入

        依赖:bean对象的创建依赖于容器

        注入:bean对象中的所有属性,由容器来注入。

【环境搭建】

1.复杂类型

public class Address {
    private String address;

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }
}

2.真实测试对象

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;
}

3.beans.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
        https://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="student" class="com.zeng.pojo.Student">
        <!-- 第一种,普通值注入, value -->
        <property name="name" value="曾雷"/>
    </bean>
</beans>

完善注入方式

<?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.zeng.pojo.Address">
        <property name="address" value="西安"/>
    </bean>

    <bean id="student" class="com.zeng.pojo.Student">
        <!-- 第一种,普通值注入, value -->
        <property name="name" value="曾雷"/>
        <!-- 第二种,bean注入, ref-->
        <property name="address" ref="address"/>
        <!-- 数组注入-->
        <property name="books" >
            <array>
                <value>西游记</value>
                <value>三国演义</value>
                <value>红楼梦</value>
                <value>水浒传</value>
            </array>
        </property>
        <!-- List-->
        <property name="hobbys">
            <list>
                <value>听歌</value>
                <value>学习</value>
                <value>敲代码</value>
            </list>
        </property>
        <!-- Map-->
        <property name="card">
            <map>
                <entry key="身份证" value="412545233645874129"/>
                <entry key="银行卡" value="6214556988874562183"/>
            </map>
        </property>
        <!-- Set-->
        <property name="games">
            <set>
                <value>LOL</value>
                <value>COC</value>
                <value>BOB</value>
            </set>
        </property>
        <!-- NULL-->
        <property name="wife">
            <null/>
        </property>
        <!-- Properties-->
        <property name="info">
            <props>
                <prop key="学号">1563245785</prop>
                <prop key="driver">12121</prop>
                <prop key="url">小法</prop>
                <prop key="username">root</prop>
                <prop key="pwd">20200304wdn</prop>
            </props>
        </property>

    </bean>
</beans>

4.测试类

public class MyTest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        Student student = (Student) context.getBean("student");
        System.out.println(student.getName());
    }
}

项目:spring-04-di

6.3拓展方式注入

我们可以通过p命名空间和c命名空间进行注入;

官方解释:

 

使用:

<?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:p="http://www.springframework.org/schema/p"
       xmlns:c="http://www.springframework.org/schema/c"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--p命名空间注入,可以直接注入属性的值:property -->
    <bean id="user" class="com.zeng.pojo.User" p:name="盘胖" p:age="18"/>
    <!--c命名空间注入,通过构造器注入:construct-args -->
    <bean id="user2" class="com.zeng.pojo.User" c:age="19" c:name="屁屁"/>
</beans>

测试:

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

注意点:

p命名和c命名空间不能直接使用,需要导入xml约束

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

6.4 Bean的作用域

 1.单例模式(singleton):Spring默认机制

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

2.原型模式(prototype):每次从容器种get的时候,都会产生一个新对象!

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

 3.其余的request,session,application这些只能在web开发中使用到。

7. Bean的自动装配

自动装配是spring满足bean依赖的一种方式

Spring会在上下文中自动寻找,并自动给bean装配属性

在Spring中有三种装配方式:

1.在xml中显示的配置

2.在java中显示的配置

3.隐式的自动装配Bean【重要】

7.1测试

环境搭建:一个人有连个宠物。 spring-05-autowired

7.2 ByName自动装配

    <bean id="dog" class="com.zeng.pojo.Dog"/>
    <bean id="cat" class="com.zeng.pojo.Cat"/>
    <!-- byName:会在容器上下文中自动查找和自己对象set方法后面的值对应的bean id!-->
    <bean id="people" class="com.zeng.pojo.People" autowire="byName">
        <property name="name" value="胖胖啊"/>

不是自动装配

    <bean id="dog" class="com.zeng.pojo.Dog"/>
    <bean id="cat" class="com.zeng.pojo.Cat"/>
    <bean id="people" class="com.zeng.pojo.People">
        <property name="name" value="胖胖啊"/>
        <property name="cat" ref="cat"/>
        <property name="dog" ref="dog"/>
    </bean>

7.3ByType自动装配


    <bean id="dog" class="com.zeng.pojo.Dog"/>
    <bean id="cat11" class="com.zeng.pojo.Cat"/>
    <!-- byName:会在容器上下文中自动查找和自己对象set方法后面的值对应的bean id!-->
    <!-- byType:会在容器上下文中自动查找和自己对象属性类型相同的bean id!-->
    <bean id="people" class="com.zeng.pojo.People" autowire="byType">
        <property name="name" value="胖胖啊"/>

    </bean>

小结:

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

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

7.4使用注解实现自动装配

使用注解须知:

1.导入约束  context约束

xmlns:context="http://www.springframework.org/schema/context"

2.配置注解的支持   <context:annotation-config/>

<?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/>

</beans>

@Autowired   直接在属性上使用即可!也可以在set方式上使用!

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

科普:

@Nullable  字段标记了这个注解,说明这个字段可以为null

测试代码

public class People {
    //如果显示的定义了Autowired的required属性为false说明这个属性可以为null否则不允许为空。
    @Autowired(required = false)
    private Dog dog;
    @Autowired
    private Cat cat;
    private String name;

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

public class People {
    //如果显示的定义了Autowired的required属性为false说明这个属性可以为null否则不允许为空。
    @Autowired
    @Qualifier(value="dog11")
    private Dog dog;
    @Autowired
    private Cat cat;
    private String name;

 @Resource注解

public class People {
    //如果显示的定义了Autowired的required属性为false说明这个属性可以为null否则不允许为空。
    @Resource(name="dog11")
    private Dog dog;
    @Resource(name="cat")
    private Cat cat;
    private String name;

 小结:

@Resource和@Autowired的区别:

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

        @Autowired通过byType的方式实现,而且必须要求这个对象存在!【常用】

        @Resource默认通过byName方式实现,如果找不到名字,则通过byType实现!如果两个都找不到则报错。

        执行顺序不同:@Autowired通过byType的方式实现,@Resource默认通过byName方式实现 

8.使用注解开发

在spring4之后要使用注解开发,必须要保证aop的包导入了。

使用注解需要导入context约束增加注解的支持。 

xmlns:context="http://www.springframework.org/schema/context"

<context:annotation-config/>

8.1 bean

8.2属性如何注入

//@Component:组件  等价于<bean id="user" class="com.zeng.pojo.User"/>
@Component
public class User {
    /*  @Value("pangpang")相当于:
    /<bean id="user" class="com.zeng.pojo.User">
    <property name="name" value="pangpang"/>
    </bean>
     */
    @Value("pangpang")
    public String name;
}

8.3衍生的注解

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

        DAO 【@Repository】

        Service【@Service】

        Controller【@Controller】

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

8.4自动装配置

@Autowired:自动装配  通过类型,名字。
- 如果@Autowired不能唯一自动装配上属性,则需要通过@Qualifier(value="XXX")
- @Nullable  字段标记了这个注解,说明这个字段可以为null
- @Resouce :自动装配通过名字,类型。

8.5作用域

//@Component:组件  等价于<bean id="user" class="com.zeng.pojo.User"/>
@Component
@Scope("prototype")
public class User {
    /*  @Value("pangpang")相当于:
    /<bean id="user" class="com.zeng.pojo.User">
    <property name="name" value="pangpang"/>
    </bean>
     */
    @Value("pangpang")
    public String name;
}

8.6小结

xml与注解

        xml更加万能,适用于任何场合,维护简单方便!

        注解 不是自己的类使用不了,维护相对复杂!

xml与注解最佳实践:

xml用来管理bean

注解值负责完成属性的注入

我们在使用的过程中,只需要注意一个问题:必须让注解生效,就需要开启注解的支持!

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

9 使用java的方式配置spring

我们现在要完全不适用spring的xml配置了,全权交给java来做

JavaConfig是spring的一个子项目,在spring4之后,它成为一个核心功能

//这里这个注解的意思,就是说明这个类被spring接管了,注册到了容器中
@Component
public class User {
    private String name;

    public String getName() {
        return name;
    }
@Value("pangpang")//属性注入值
    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                '}';
    }
}

配置文件

package com.zeng.config;

import com.zeng.pojo.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

//@Configuration代表这是一个配置类,就和之前的bean.xml一样
//这个也会被spring容器托管,注册到容器中,因为它本来也是一个@Component
@Configuration
@ComponentScan("com.zeng.pojo")
@Import(ZengConfig2.class)
public class ZengConfig {

    //注册一个Bean,就相当于我们之前写的一个bean标签
    //这个方法的名字,就相当于bean标签中的id属性
    //这个方法的返回值,就相当于bean标签中的class属性

    @Bean
    public User getUser(){
        return new User();//就是返回要注入到bean中的对象
   }
}

测试类

import com.zeng.pojo.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

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

这种java的配置方式,在springBoot中随从可见。

10 代理模式

为什么要学代理模式?因为它是SpringAOP的底层!【SpringAOP和SpringMVC】

代理模式的类型:

        静态代理

        动态代理

10.1 代理模式

角色分析

        抽象角色:一般会使用接口或抽象类来解决

        真实角色:被代理的角色

        代理角色:代理真实角色,代理真实角色后,我们一般会做一些附属操作

        客户:访问代理对象的人

3.代理角色

 代理模式的好处:

        可以使真实角色的操作更加纯粹不用去关注一些公众的业务

        公共也就交给代理角色,实现业务的分工

        公共业务发生扩展的时候方便集中管理

缺点:

        一个真实角色就会产生一个代理角色,代码量翻倍,工作效率降低

10.2 加深理解

代码对应spring-08-demo02 

10.3 动态代理

动态代理和静态代理一样

动态代理是代理类动态生成的,不是我们直接写好的

动态代理分为两大类,基于接口的动态代理,基于类的动态代理

        基于接口---JDK动态代理【我们在这里使用】

        基于类---cglib

        java字节码实现:javassist

需要了解两个类:Proxy:代理  InvocationHandler:调试处理程序

package com.zeng.demo4;

import com.zeng.demo3.Rent;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

//我们会用这个类自动生成接口
public class ProxyInvocationHandler implements InvocationHandler {
    //被代理的接口
    private Object target;

    public void setTarget(Object target) {
        this.target = target;
    }

    //生成得到代理类
    public Object getProxy(){
        return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(),this);
    }
    //处理代理实例,并返回结果
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    //动态代理的本质就是使用反射机制
        log(method.getName());
        Object result = method.invoke(target, args);
        return result;
    }

public void log(String msg){
    System.out.println("执行了"+msg+"方法");
}

}

动态代理的好处:

        可以使真实角色的操作更加纯粹不用去关注一些公众的业务

        公共也就交给代理角色,实现业务的分工

        公共业务发生扩展的时候方便集中管理

        一个动态代理类代理的是一个接口一般就对应一个业务

        一个动态代理类可以代理多个类,只要是实现了同一个接口

11 AOP

11.1 什么是AOP

 11.2 AOP在spring中的作用

 

 

 11.3 使用spring实现AOP

【使用AOP植入需要导入一个依赖包】

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

方式一:使用Spring的API接口【主要是springAPI接口实现】

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

    <!--方式一:使用原生的Spring API接口-->
    <!--注册aop :需要导入aop的约束-->
<!--    <aop:config>
        &lt;!&ndash;切入点:expression:表达式execution(要执行的位置!(* *  * * *) &ndash;&gt;
        <aop:pointcut id="pointcut" expression="execution(* com.zeng.service.UserServiceImpl.*(..))"/>
        &lt;!&ndash;执行环绕增加&ndash;&gt;
        <aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
        <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>

    </aop:config>-->

方式二:使用自定义类实现AOP【主要是切面定义】

<!--方式二:自定义类-->
    <bean id="diy" class="com.zeng.diy.DiyPointCut"/>
    <aop:config>
        <!--自定义切面, ref要引用到类-->
        <aop:aspect ref="diy">
            <!--切入点-->
            <aop:pointcut id="point" expression="execution(* com.zeng.service.UserServiceImpl.*(..))"/>
            <!--通知-->
           <aop:before method="before" pointcut-ref="point"/>
            <aop:after method="after" pointcut-ref="point"/>
        </aop:aspect>
    </aop:config>

方式三:使用注解实现

    <!--方式三:使用注解实现-->
    <bean id="annotationPointCut" class="com.zeng.diy.AnnotationPointCut"/>
    <!--开启注解支持-->
    <aop:aspectj-autoproxy/>
package com.zeng.diy;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

/**
 * 使用注解实现AOP
 */
@Aspect//标注这个类为一切面
public class AnnotationPointCut {
    @Before("execution(* com.zeng.service.UserServiceImpl.*(..))")
    public void before(){
        System.out.println("========方法执行前==========");
    }
    @After("execution(* com.zeng.service.UserServiceImpl.*(..))")
    public void after(){
        System.out.println("方法执行后");
    }
    @Around("execution(* com.zeng.service.UserServiceImpl.*(..))")
    public void around(ProceedingJoinPoint jp) throws Throwable {
        System.out.println("环绕前");
        Signature signature = jp.getSignature();//获得签名
        System.out.println("signature"+signature);
        //执行方法
        Object proceed = jp.proceed();
        System.out.println("环绕后");
        System.out.println(proceed);

    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值