1、使用注解开发

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

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xmlns:context="http://www.springframework.org/schema/context"
  5. xsi:schemaLocation="http://www.springframework.org/schema/beans
  6. https://www.springframework.org/schema/beans/spring-beans.xsd
  7. http://www.springframework.org/schema/context
  8. https://www.springframework.org/schema/context/spring-context.xsd">
  9. <context:annotation-config/>
  10. </beans>
  1. bean
  2. 属性如何注入

    1. // 等价于 <bean id="user" class="com.shuai.pojo.User"/>
    2. // @Component 组件
    3. @Component
    4. public class User {
    5. public String name;
    6. // 相当于 <property name="name" value="少帅"/>
    7. @Value("少帅")
    8. public void setName(String name) {
    9. this.name = name;
    10. }
    11. }
  1. 衍生的注解
    @Component 有几个衍生注解,我们在web开发中,会按照mvc三层架构分层
    • dao 【@Repository】
    • service 【@Service】
    • controller 【@Controller】
      这四个注解功能都是一样的,都是代表将某个类注册到Spring中,装配Bean
  2. 自动装配置
    1. @Autowired:自动装配通过类型,名字。如果Autowired不能唯一自动装配上属性,则需要通过@Qualifier(value = "xxx")去配置。
    2. @Nullable 字段标记了了这个注解,说明这个字段可以为null;
    3. @Resource:自动装配通过名字,类型。
  1. 作用域
    1. @Component
    2. @Scope("prototype")
    3. public class User {
    4. @Value("少帅")
    5. public String name;
    6. }
  1. 小结
    xml与注解:
    • xml更加万能,适用于任何场合!维护简单方便
    • 注解不是自己类使用不了,维护相对复杂!

xml与注解最佳实践:

  • xml用来管理bean;
  • 注解只负责完成属性的注入;
  • 我们在使用的过程中,只需要注意一个问题:必须让注解生效,就需要开启注解的支持
    1. <!--指定要扫描的包,这个包下的注解就会生效-->
    2. <context:component-scan base-package="com.shuai"/>
    3. <context:annotation-config/>

2、使用Java的方式配置Spring

  • 实体类

    1. // 这里这个注解的意思,就是说明这个类型被Spring接管了,注册到了容器中
    2. @Component
    3. public class User {
    4. private String name;
    5. public String getName() {
    6. return name;
    7. }
    8. @Value("少帅") // 属性注入值
    9. public void setName(String name) {
    10. this.name = name;
    11. }
    12. @Override
    13. public String toString() {
    14. return "User{" +
    15. "name='" + name + '\'' +
    16. '}';
    17. }
    18. }
  • 配置文件

    1. // 这个也被Spring容器托管,注册到容器中,因为本身就是一个@Component
    2. // @Configuration代表这是一个配置类,就和我们之前看的beans.xml
    3. @Configuration
    4. @ComponentScan("com.shuai.pojo")
    5. public class ShuaiConfig {
    6. // 注册一个bean,就相当于我们之前写的一个bean标签
    7. // 这个方法的名字,就相当于bean标签下的id属性
    8. // 这个方法的返回值,就相当于bean标签中的class属性
    9. @Bean
    10. public User getUser(){
    11. return new User(); // 就是返回要注入到Bean的对象!
    12. }
    13. }
  • 测试
    1. public class MyTest {
    2. public static void main(String[] args) {
    3. ApplicationContext context = new AnnotationConfigApplicationContext(ShuaiConfig.class);
    4. User getUser = (User) context.getBean("getUser");
    5. System.out.println(getUser.getName());
    6. }
    7. }

3、代理模式

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

代理模式的分类:

  • 静态代理
  • 动态代理

3.1、静态代理

角色分析:

  • 抽象角色:一般会使用接口或者抽象类来解决
  • 真实角色:被代理的角色
  • 代理角色:代理真实角色,代理真实角色后,我们一般会做一些附属操作
  • 客户:访问代理对象的人!

代理步骤:

  1. 接口
    1. //租房
    2. public interface Rent {
    3. public void rent();
    4. }
  1. 真实角色
    1. //房东
    2. public class Host implements Rent{
    3. public void rent() {
    4. System.out.println("房东出租房子!");
    5. }
    6. }
  1. 代理角色

    1. public class Proxy implements Rent{
    2. private Host host;
    3. public Proxy() {
    4. }
    5. public Proxy(Host host) {
    6. this.host = host;
    7. }
    8. public void rent() {
    9. seeHouse();
    10. host.rent();
    11. Contract();
    12. Charge();
    13. }
    14. // 看房
    15. public void seeHouse(){
    16. System.out.println("中介带你看房");
    17. }
    18. // 签合同
    19. public void Contract(){
    20. System.out.println("签订合同!!!");
    21. }
    22. // 收费
    23. public void Charge(){
    24. System.out.println("中介收费");
    25. }
    26. }
  1. 客户端访问代理角色

    1. public class Client {
    2. public static void main(String[] args) {
    3. // 房东要租房子
    4. Host host = new Host();
    5. // 代理,中介帮房东出租房子,收取小费
    6. Proxy proxy = new Proxy(host);
    7. // 你不用面对房东,直接找中介租房即可!
    8. proxy.rent();
    9. }
    10. }

代理模式的好处:

  • 可以使真实角色的操作更加纯粹!不用去关注一些公共的业务
  • 公共也就给代理角色!实现了业务的分工!
  • 公共业务发生扩展的时候,方便集中管理!

缺点:

  • 一个真实角色就会产生一个代理角色;代码量会翻倍开发效率会变低

3.2、加深理解

代码步骤:

  1. 接口
    1. public interface UserService {
    2. public void add();
    3. public void delete();
    4. public void update();
    5. public void query();
    6. }
  1. 真实角色

    1. public class UserServiceImpl implements UserService{
    2. public void add() {
    3. System.out.println("添加一个用户");
    4. }
    5. public void delete() {
    6. System.out.println("删除一个用户");
    7. }
    8. public void update() {
    9. System.out.println("更新一个用户");
    10. }
    11. public void query() {
    12. System.out.println("查找一个用户");
    13. }
    14. }
  1. 代理角色

    1. public class UserServiceProxy implements UserService{
    2. private UserServiceImpl userService;
    3. public void setUserService(UserServiceImpl userService) {
    4. this.userService = userService;
    5. }
    6. public void add() {
    7. log("add");
    8. userService.add();
    9. }
    10. public void delete() {
    11. log("delete");
    12. userService.delete();
    13. }
    14. public void update() {
    15. log("update");
    16. userService.update();
    17. }
    18. public void query() {
    19. log("query");
    20. userService.query();
    21. }
    22. public void log(String msg){
    23. System.out.println("[debug] 使用一个"+msg+"方法");
    24. }
    25. }
  1. 客户端访问代理角色

    1. public class Client {
    2. public static void main(String[] args) {
    3. UserServiceImpl userService = new UserServiceImpl();
    4. UserServiceProxy proxy = new UserServiceProxy();
    5. proxy.setUserService(userService);
    6. proxy.add();
    7. }
    8. }

3.3 动态代理

  • 动态代理和静态代理角色一样
  • 动态代理的代理类是动态生成的,不是我们直接写好的!
  • 动态代理分为两大类:基于接口的动态代理,基于类的动态代理
  • 基于接口 — JDK动态代理【我们在这里使用】
  • 基于类:cglib
  • java字节码实现:javassist

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

代码步骤:

  1. 接口
    1. // 租房
    2. public interface Rent {
    3. public void rent();
    4. }
  1. 真实角色
    1. // 房东
    2. public class Host implements Rent {
    3. public void rent() {
    4. System.out.println("房东要出租房子!");
    5. }
    6. }
  1. ProxyInvocationHandler类

    1. // 我们用这个类,自动生成代理类!
    2. public class ProxyInvocationHandler implements InvocationHandler{
    3. // 被代理的接口
    4. private Rent rent;
    5. public void setRent(Rent rent) {
    6. this.rent = rent;
    7. }
    8. // 生成得到代理类
    9. public Object getProxy(){
    10. return Proxy.newProxyInstance(this.getClass().getClassLoader(),rent.getClass().getInterfaces(), this);
    11. }
    12. // 处理代理实例,并返回结果
    13. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    14. // 动态代理的本质,就是使用反射机制实现!
    15. Object result = method.invoke(rent, args);
    16. seeHouse();
    17. fee();
    18. return result;
    19. }
    20. public void seeHouse(){
    21. System.out.println("中介带看房子");
    22. }
    23. public void fee(){
    24. System.out.println("中介收取小费");
    25. }
    26. }
  1. 测试

    1. public class Client {
    2. public static void main(String[] args) {
    3. // 真实角色
    4. Host host = new Host();
    5. // 代理角色:现在没有
    6. ProxyInvocationHandler pih = new ProxyInvocationHandler();
    7. // 通过调用程序处理角色来处理我们要调用的接口对象
    8. pih.setRent(host);
    9. Rent proxy = (Rent) pih.getProxy();
    10. proxy.rent();
    11. }
    12. }

在此,我们可以提炼出ProxyInvocationHandler作为工具类

  1. // 我们会用这个类,自动生成代理类!
  2. public class ProxyInvocationHandler implements InvocationHandler {
  3. // 被代理的接口!
  4. private Object target;
  5. public void setTarget(Object target) {
  6. this.target = target;
  7. }
  8. // 得到代理类
  9. public Object getProxy(){
  10. return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(), this);
  11. }
  12. // 处理代理实例,并返回结果
  13. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  14. log(method.getName());
  15. Object result = method.invoke(target, args);
  16. return result;
  17. }
  18. public void log(String msg){
  19. System.out.println("执行了"+msg+"方法");
  20. }
  21. }

测试

  1. public class Client {
  2. public static void main(String[] args) {
  3. // 真实角色
  4. UserServiceImpl userService = new UserServiceImpl();
  5. // 代理角色,不存在
  6. ProxyInvocationHandler pih = new ProxyInvocationHandler();
  7. pih.setTarget(userService); // 设置代理的对象
  8. // 动态生成代理类
  9. UserService proxy = (UserService) pih.getProxy();
  10. proxy.delete();
  11. }
  12. }

动态代理的好处:

  • 可以使真实角色的操作更加纯粹!不用去关注一些公共的业务
  • 公共角色就交给代理角色!实现了业务的分工!
  • 公共业务发生扩展的时候,方便集中管理!
  • 一个动态代理类代理的是一个接口,一般就是对应的一类业务
  • 一个动态代理类可以代理多个类,只要是实现了同一个接口即可!