注解(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>
<!–切入点:expression:表达式execution(要执行的位置!(* * * * *) –>
<aop:pointcut id="pointcut" expression="execution(* com.zeng.service.UserServiceImpl.*(..))"/>
<!–执行环绕增加–>
<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);
}
}