El mòdul anterior va acabar amb una promesa: «Has escrit versions en miniatura de gairebé tots ells amb les teves pròpies mans. Ara faràs servir els de veritat.»

Aquesta lliçó és el pont. Abans d'escriure la primera anotació de Spring o la primera entitat d'Hibernate, cal entendre què és exactament un framework, en què es diferencia d'una llibreria, què et dóna i què et treu i —sobretot— com funciona per dins, perquè la resposta a aquesta última pregunta ja la saps: anotacions, reflexió, proxies dinàmics i generació de codi. Exactament allò que vas construir al mòdul 10.

Això importa per una raó molt pràctica. La diferència entre un desenvolupador que fa servir Spring i un que entén Spring no està en quantes anotacions es coneix de memòria: està en el fet que quan alguna cosa falla —i fallarà— el primer busca en un fòrum i el segon raona sobre què està fent el contenidor. Quan vegis que una crida a un mètode @Transactional des d'un altre mètode de la mateixa classe no obre transacció, tu sabràs per què: perquè el proxy dinàmic que vas escriure a 10-03 té exactament el mateix forat, i el vas veure amb els teus ulls.

A més, hi ha una decisió professional que ningú t'ensenya i que prendràs desenes de vegades a la teva carrera: afegir o no una dependència. És una decisió amb conseqüències de seguretat, de manteniment i de pes. Aquesta lliçó et dóna criteris reals per prendre-la.

En acabar sabràs distingir llibreria de framework i explicar la inversió de control amb un exemple que vas escriure tu, tindràs un mapa de l'ecosistema Java per categories, sabràs com s'avalua una dependència abans de ficar-la al teu pom.xml, entendràs què és Maven Central i què signifiquen les coordenades groupId:artifactId:version, i coneixeràs el risc de la cadena de subministrament de programari amb un cas real que va paralitzar la indústria durant setmanes.

Contingut

  1. El punt de partida: BiblioTech fet a mà
  2. Llibreria enfront de framework: qui crida qui
  3. La inversió del control, explicada amb el teu propi ContenidorSimple
  4. Què aporta un framework
  5. Què costa un framework
  6. Com se sosté la màgia: els quatre mecanismes
  7. El mapa: allò que vas escriure a mà enfront d'allò que fa el framework de veritat
  8. Mapa de l'ecosistema Java per categories
  9. Com es tria una dependència
  10. La pregunta prèvia: la necessito de veritat?
  11. Maven Central i les coordenades
  12. Versionat semàntic
  13. El cost de la seguretat de la cadena de subministrament
  14. Log4Shell: què va passar de veritat
  15. Auditar dependències a la pràctica
  16. Quin framework aprendre primer
  17. Per què aquest curs tria Spring Boot
  18. El pla del mòdul 11
  19. Errors comuns i consells
  20. Exercicis

  1. El punt de partida: BiblioTech fet a mà

Abans de mirar endavant, mira un cop més el que tens. BiblioTech, en acabar el mòdul 10, és un projecte respectable: domini segellat, repositoris genèrics, streams, java.time, fils virtuals, un contenidor d'injecció de dependències casolà i tres proxies dinàmics.

I té sis deutes declarats:

Deute Estat actual Què falta
Injecció de dependències ContenidorSimple, 150 línies Àmbits, cicle de vida, configuració per entorn, transaccions
Persistència Fitxers CSV Consultes, índexs, transaccions, integritat referencial
JSON indexOf a mà (09-06) Un analitzador de veritat
Codi repetitiu Getters, equals, hashCode, toString a mà Generació automàtica
Logging java.util.logging Una façana estàndard de l'ecosistema
Construcció javac a mà Dependències, fases, empaquetatge, reproductibilitat
Proves Cap Tot

Cadascuna d'aquestes files és una lliçó d'aquest mòdul. Però fixa't en una cosa: cap d'aquests deutes és de lògica de negoci. Cap no té a veure amb préstecs, multes, reserves o catàlegs. Tots són lampisteria: coses que tota aplicació necessita i que cap aplicació no vol escriure.

Aquesta observació és, literalment, la definició del problema que resolen els frameworks.

  1. Llibreria enfront de framework: qui crida qui

La distinció se sol explicar malament. No és una qüestió de mida ni de complexitat. Hi ha llibreries enormes i frameworks minúsculs. La diferència és de direcció de les crides.

  • Una llibreria és codi que crides tu. Tu tens el control del flux: decideixes quan, on i amb quins arguments. java.util.Collections, Jackson o Apache Commons són llibreries: crides Collections.sort(llista) quan et convé.
  • Un framework és codi que et crida a tu. El framework té el control del flux: defineix l'estructura de l'aplicació, arrenca i, en determinats punts, invoca el teu codi. Tu omples buits.

Aquesta inversió té un nom clàssic, el Principi de Hollywood: "No ens truquis, ja et trucarem nosaltres."

graph LR
    subgraph "LLIBRERIA"
        A1["El teu codi<br/>(controla el flux)"] -->|crida| B1["Jackson<br/>Commons<br/>Guava"]
        B1 -->|retorna| A1
    end
    subgraph "FRAMEWORK"
        A2["Spring<br/>JUnit<br/>Servlet API"] -->|crida| B2["El teu codi<br/>(omple buits)"]
        B2 -->|retorna| A2
    end

Un exemple concret que ja coneixes, de 09-06. Quan vas escriure el ClientMetadades amb HttpClient:

// LLIBRERIA: tu decideixes quan cridar
HttpResponse<String> resposta = client.send(peticio, BodyHandlers.ofString());
String cos = resposta.body();

Tu ho controles tot. HttpClient és una llibreria.

I ara, un exemple de framework que veuràs a 11-04:

class CalculadoraMultesTest {
    @Test
    void multaDeCincDiesSonCincEuros() {
        // ...
    }
}

On és el main? Qui crida multaDeCincDiesSonCincEuros()? Tu no. El crida JUnit. Tu només has escrit un mètode i li has posat una etiqueta. JUnit escaneja les teves classes, troba els mètodes anotats amb @Test, crea una instància per a cadascun i els invoca. Això és un framework.

Compara els dos models:

Aspecte Llibreria Framework
Control del flux Teu Del framework
Qui crida qui Tu → llibreria Framework → tu
Estructura del teu codi Lliure Imposada (convencions, anotacions, interfícies)
Cost de substituir-la Baix (aïlles la crida) Alt (impregna l'arquitectura)
Exemples Jackson, Guava, Commons, SLF4J Spring, JUnit, Hibernate, Quarkus
Punt d'entrada Mètodes que invoques Hooks: anotacions, interfícies, fitxers de configuració

Un matís honest: la frontera no sempre és nítida. Spring és un framework, però RestTemplate dins de Spring és una llibreria. Hibernate és un framework quan gestiona el cicle de vida de les teves entitats, i una llibreria quan crides entityManager.find(...). L'útil no és classificar, sinó preguntar-se a cada punt: qui controla el flux aquí?

  1. La inversió del control, explicada amb el teu propi ContenidorSimple

La inversió de control (IoC, Inversion of Control) és el principi general: cedir el control del flux a un altre component. La injecció de dependències (DI, Dependency Injection) és la forma concreta d'IoC que més faràs servir: en comptes que un objecte creï les seves pròpies dependències, li les donen fetes.

Això ho vas escriure tu a 10-03. Abans del ContenidorSimple, GestorPrestecs feia això:

// ABANS: l'objecte crea les seves propies dependencies. Control NO invertit.
public class GestorPrestecs {

    private final Repositori<Prestec> repositori;
    private final CalculadoraMultes calculadora;
    private final ServeiAvisos avisos;

    public GestorPrestecs() {
        // El propi gestor decideix QUINA implementacio fa servir i COM construir-la.
        this.repositori = new MagatzemPrestecs(Path.of("dades/prestecs.csv"));
        this.calculadora = new CalculadoraMultes(Clock.systemDefaultZone());
        this.avisos = new ServeiAvisos("smtp.nexussoftware.com", 587);
    }
}

Problemes d'aquest codi, tots reals:

  1. No es pot provar. Per provar el càlcul d'una multa necessites un fitxer CSV en disc i un servidor SMTP.
  2. No es pot canviar d'implementació. Si demà el magatzem és una base de dades, cal editar GestorPrestecs.
  3. No es pot configurar per entorn. L'amfitrió SMTP de desenvolupament i el de producció són diferents, i estan escrits a foc.
  4. El rellotge és el del sistema. Aquest Clock.systemDefaultZone() fa impossible provar un venciment sense esperar 15 dies. Just el que 10-05 volia evitar.

Després del ContenidorSimple:

// DESPRES: l'objecte DECLARA el que necessita. Control invertit.
public class GestorPrestecs {

    private final Repositori<Prestec> repositori;
    private final CalculadoraMultes calculadora;
    private final ServeiAvisos avisos;

    public GestorPrestecs(Repositori<Prestec> repositori,
                          CalculadoraMultes calculadora,
                          ServeiAvisos avisos) {
        this.repositori = repositori;
        this.calculadora = calculadora;
        this.avisos = avisos;
    }
}

GestorPrestecs ja no sap d'on surten els seus col·laboradors. Només sap què necessita. Algú de fora —el contenidor— resol el graf de dependències, construeix tot en l'ordre correcte i li passa les peces.

Visualment, el canvi és aquest:

graph TD
    subgraph "SENSE inversio de control"
        G1["GestorPrestecs"] -->|new| R1["MagatzemPrestecs"]
        G1 -->|new| C1["CalculadoraMultes"]
        G1 -->|new| A1["ServeiAvisos"]
    end
    subgraph "AMB inversio de control"
        CT["Contenidor IoC"] -->|construeix| R2["MagatzemPrestecs"]
        CT -->|construeix| C2["CalculadoraMultes"]
        CT -->|construeix| A2["ServeiAvisos"]
        CT -->|construeix i injecta| G2["GestorPrestecs"]
        R2 -.->|injectat| G2
        C2 -.->|injectat| G2
        A2 -.->|injectat| G2
    end

El teu ContenidorSimple feia això: escanejava les classes anotades amb @Component, mirava els seus constructors amb reflexió, resolia recursivament cada paràmetre, detectava cicles i emmagatzemava els singletons en memòria cau. Cent cinquanta línies.

L'ApplicationContext de Spring fa exactament el mateix. I unes quantes coses més:

Capacitat El teu ContenidorSimple ApplicationContext de Spring
Escanejar components Sí, @Component Sí, @Component i estereotips
Injecció per constructor Sí (recomanada)
Injecció per setter i camp No
Detecció de cicles Sí, amb excepció Sí, amb missatge molt millor
Singleton Sí, un Map Sí, més 5 àmbits addicionals
Àmbit prototip / petició / sessió No
Cicle de vida (@PostConstruct / @PreDestroy) No
Configuració per entorn (perfils) No Sí, @Profile
Propietats externalitzades No Sí, @Value, @ConfigurationProperties
Resolució d'ambigüitat No (fallava amb 2 implementacions) Sí, @Qualifier, @Primary
Injectar totes les implementacions en una List<T> No
Transaccions declaratives No Sí, @Transactional
Programació orientada a aspectes Tres proxies escrits a mà Sí, integrada
Creació mandrosa No Sí, @Lazy
Esdeveniments entre components No Sí, ApplicationEventPublisher
Arrencada d'aplicació web No

Cap d'aquestes files addicionals no és lògica de negoci. Totes són coses que necessitaries escriure si la teva aplicació creixés. Això és el que compres.

  1. Què aporta un framework

Quatre coses concretes, per ordre d'importància real.

1. Codi no diferenciador ja resolt. Hi ha una distinció útil entre codi diferenciador (el que resol el problema pel qual existeix la teva empresa: a BiblioTech, les regles de préstecs, multes i reserves) i codi de lampisteria (el que necessita qualsevol aplicació: arrencar, configurar-se, parlar amb una base de dades, atendre HTTP, registrar traces). El codi de lampisteria no aporta valor a ningú i tanmateix s'emporta la major part del temps quan l'escrius tu. Un framework et torna aquest temps.

2. Convencions compartides. Si contractes un desenvolupador Java amb experiència en Spring, entén l'estructura del teu projecte en una tarda. Si BiblioTech fes servir el teu ContenidorSimple casolà, trigaria una setmana a entendre un contenidor que només existeix a la teva empresa i del qual no hi ha documentació, cursos ni respostes en fòrums. Les convencions són un actiu econòmic.

3. Ecosistema. Quan tries Spring, no tries només un contenidor: tries Spring Data (persistència), Spring Security (autenticació), Spring Cloud (sistemes distribuïts), Actuator (observabilitat) i centenars d'integracions que ja funcionen juntes. La integració ja està feta i provada, i això val més que qualsevol característica individual.

4. Seguretat mantinguda. Quan apareix una vulnerabilitat en la gestió de peticions HTTP, l'equip de Spring publica un pedaç i tu actualitzes una versió. Si aquesta lògica és teva, la vulnerabilitat la descobreixes quan te l'exploten. Aquest punt se sol infravalorar i és probablement el més important en producció.

  1. Què costa un framework

Un framework no és gratis. Quatre costos, també reals.

1. Corba d'aprenentatge. Spring té més de vint anys de superfície acumulada. Ser productiu porta setmanes; ser competent, mesos. I bona part d'aquest aprenentatge no és transferible: aprendre @Transactional no t'ensenya res sobre bases de dades, t'ensenya sobre Spring.

2. Acoblament. Un framework impregna l'arquitectura. Migrar una aplicació de Spring a Quarkus no és canviar una dependència: és reescriure la capa de configuració, la d'arrencada, la de proves i probablement part del domini. Per això convé mantenir el domini net d'anotacions del framework sempre que sigui possible — una idea que es desenvolupa a 12-02.

3. Màgia difícil de depurar. Quan un @Autowired no injecta, o una transacció no fa rollback, o una entitat es desa sola sense que cridis save, la causa és en codi que tu no vas escriure, invocat per reflexió des d'un punt que no apareix a la teva traça. Aquesta és exactament la raó que el mòdul 10 anés abans que aquest: si saps com funciona la màgia, pots depurar-la.

4. Pes. Un jar executable de Spring Boot amb web i JPA ronda els 40-50 MB i arrenca en 1-3 segons. Per a un servei de llarga vida és irrellevant. Per a una funció serverless que arrenca a cada petició o un CLI que ha de respondre en 50 ms, és desqualificador — i aquí és on entren Quarkus, Micronaut o la compilació nativa amb GraalVM que es va esmentar a 10-07.

Resumit:

Guanyes Pagues
Setmanes de lampisteria resolta Setmanes de corba d'aprenentatge
Convencions que qualsevol entén Acoblament a una arquitectura concreta
Un ecosistema integrat i provat Comportament implícit difícil de depurar
Pedaços de seguretat mantinguts Superfície d'atac de tercers
Menys codi propi per mantenir Més pes, més arrencada, més memòria

La conclusió professional no és "els frameworks són bons" ni "són dolents": és que la decisió depèn del context, i que qui no entén el que hi ha a sota no pot prendre-la.

  1. Com se sosté la màgia: els quatre mecanismes

Aquí és on el mòdul 10 es cobra del tot. Tot el que un framework Java fa "per art de màgia" es recolza en quatre mecanismes, i els quatre els coneixes.

Mecanisme 1: anotacions (10-02)

Les anotacions són metadades: etiquetes que no fan res per si soles. @Service no arrenca res. @Entity no crea cap taula. @Test no executa res. Són marques inertes que algú ha de llegir.

Ho vas aprendre construint @CampCsv i @Auditable. I vas aprendre la condició imprescindible:

@Retention(RetentionPolicy.RUNTIME)   // sense aixo, l'anotacio NO existeix en execucio
@Target(ElementType.TYPE)
public @interface Component { }

Tota anotació de framework que es llegeixi en execució porta @Retention(RUNTIME). Obre el codi font de @Service de Spring o d'@Entity de Jakarta Persistence: hi és.

Mecanisme 2: reflexió (10-03)

Algú ha de llegir les etiquetes. Aquest algú fa servir reflexió: Class.forName, getDeclaredFields, isAnnotationPresent, getDeclaredConstructor().newInstance(), invoke, setAccessible(true).

El teu ExportadorAnotat recorria els camps de qualsevol objecte buscant @CampCsv. Hibernate recorre els camps de qualsevol entitat buscant @Column. És el mateix bucle.

Mecanisme 3: proxies dinàmics (10-03)

Quan el framework necessita afegir comportament al voltant del teu mètode sense tocar el teu codi —transaccions, seguretat, memòria cau, reintents, mètriques—, no modifica la teva classe: l'embolcalla. En vas escriure tres:

// El teu ProxyAuditoria de 10-03
Object proxy = Proxy.newProxyInstance(
    interficie.getClassLoader(),
    new Class<?>[] { interficie },
    (p, metode, args) -> {
        if (metode.isAnnotationPresent(Auditable.class)) {
            registre.anotarInici(metode.getName());
        }
        Object resultat = metode.invoke(objectiu, args);   // crida real
        // ... post-processat
        return resultat;
    });

Quan a 11-02 vegis @Transactional, no veuràs res de nou: veuràs aquest mateix InvocationHandler amb iniciar transacció abans i confirmar o revertir després. I veuràs també el mateix forat: si l'objectiu es crida a si mateix internament, la crida no passa pel proxy i l'aspecte no s'aplica. Aquest detall és la causa d'un percentatge enorme dels "el meu @Transactional no funciona" del món.

Nota tècnica: els proxies JDK que vas escriure només funcionen sobre interfícies. Quan la classe no n'implementa cap, Spring fa servir CGLIB, que genera en temps d'execució una subclasse de la teva classe i sobreescriu els seus mètodes. D'aquí una conseqüència pràctica: una classe o un mètode final no es pot proxiar amb CGLIB, i per això de vegades el teu @Transactional sobre un mètode final no fa absolutament res.

Mecanisme 4: generació de codi

Hi ha dos moments possibles.

  • En temps de compilació, mitjançant un processador d'anotacions (javax.annotation.processing, vist a 10-02). És el que fa Lombok: no hi ha màgia en execució, el .class ja conté els getters. També MapStruct i Micronaut.
  • En temps d'execució, generant bytecode al vol amb ASM, ByteBuddy o CGLIB. És el que fan Spring, Hibernate i Mockito.

Cada opció té les seves conseqüències:

Mecanisme Quan actua Cost en arrencada Depurable Exemples
Anotacions + reflexió Execució Mitjà (escaneig) Regular Spring, Hibernate, JUnit, Jackson
Proxy dinàmic JDK Execució Baix Regular (traces amb $Proxy0) @Transactional, Spring Data
Generació de subclasse (CGLIB/ByteBuddy) Execució Mitjà Difícil Spring AOP sobre classes, Mockito
Processador d'anotacions Compilació Cap Fàcil (el codi existeix) Lombok, MapStruct, Micronaut

La tendència actual, precisament pel cost d'arrencada i per la compatibilitat amb la compilació nativa de GraalVM, és moure feina de l'execució a la compilació. Quarkus i Micronaut van néixer amb aquesta idea, i Spring 6 l'ha adoptada parcialment amb AOT.

  1. El mapa: allò que vas escriure a mà enfront d'allò que fa el framework de veritat

Aquesta taula és el resum del mòdul 10 llegit des del mòdul 11. És, probablement, la taula més important d'aquesta lliçó.

Allò que vas escriure a mà Lliçó Allò que fa el framework de veritat Es veu a
ContenidorSimple amb @Component i @Injectar 10-03 ApplicationContext de Spring amb @Component i @Autowired 11-02
ProxyAuditoria, ProxyReintents, ProxyCronometre 10-03 Spring AOP, @Transactional, @Retryable, @Cacheable 11-02
ExportadorAnotat que llegeix @CampCsv per reflexió 10-03 Hibernate llegint @Column, Jackson llegint @JsonProperty 11-03, 11-07
ValidadorAnotat amb @Validar 10-03 Jakarta Bean Validation (@NotNull, @Size, @Email) 11-02
LectorCsv / EscriptorCsv a mà 07-07 OpenCSV, Commons CSV — i, encara millor, una base de dades 11-03, 11-07
MagatzemPrestecs sobre fitxers 07-06 Hibernate / JPA sobre una base de dades relacional 11-03
Repositori<T extends Identificable> genèric 10-01 JpaRepository<T, ID> de Spring Data, implementat amb proxies 11-03
Anàlisi de JSON amb indexOf 09-06 Jackson ObjectMapper 11-07
Getters, equals, hashCode, toString a mà 03-09 Lombok (o record, que ja fas servir) 11-07
ConfiguracioLog amb java.util.logging 06-07 SLF4J + Logback 11-07
Configuracio / ReglesNegoci amb Properties 07-07 application.yml, @ConfigurationProperties, perfils 11-02
main que imprimeix i un humà que mira totes JUnit 5 + AssertJ + Mockito 11-04, 11-06
javac amb classpath a mà 01-02 Maven 11-05
AturadaOrdenada amb shutdown hooks 08-05 Cicle de vida del contenidor, @PreDestroy 11-02

Llegeix-la en les dues direccions. D'esquerra a dreta, és el teu full de ruta. De dreta a esquerra, és la resposta a la pregunta «què està fent Spring aquí?».

  1. Mapa de l'ecosistema Java per categories

L'ecosistema Java és enorme i a un nouvingut li resulta aclaparador. En realitat s'ordena bé en vuit categories, i a cadascuna hi ha dues o tres opcions dominants.

Construcció i dependències

Eina Què és Quan Es veu a
Maven Estàndard de facto. XML declaratiu, cicle de vida fix Per defecte a l'empresa 11-05
Gradle DSL en Groovy o Kotlin, memòria cau i incremental Projectes grans, Android 11-05 (comparat)
Ant Històric, imperatiu Només llegat

Injecció de dependències i aplicacions

Framework Què és Fort en Es veu a
Spring / Spring Boot L'ecosistema dominant Tot; comunitat enorme 11-02
Quarkus Natiu al núvol, arrencada en mil·lisegons Contenidors, serverless esmentat
Micronaut DI resolta en compilació Arrencada i memòria mínimes esmentat
Jakarta EE L'estàndard (CDI, JAX-RS, JPA) Servidors d'aplicacions 11-03 (JPA)

Persistència

Llibreria Enfocament Quan Es veu a
JPA / Hibernate ORM: objectes ↔ taules Domini ric, CRUD 11-03
Spring Data JPA Repositoris per convenció sobre JPA Amb Spring 11-03
jOOQ SQL amb tipus verificats en compilació SQL complex i control total esmentat
MyBatis SQL en XML o anotacions, mapatge explícit Consultes a mida esmentat
JDBC / JdbcTemplate Directe, sense ORM Consultes puntuals, rendiment 11-03 (línia base)

Proves

Llibreria Per a què Es veu a
JUnit 5 Marc de proves 11-04
Mockito 5 Dobles de prova 11-06
AssertJ Assercions fluides i llegibles 11-04, 11-06
Testcontainers Base de dades i serveis reals a Docker 11-06, 12-05
WireMock Simular APIs HTTP esmentat
JaCoCo Cobertura 12-05

Serialització

Llibreria Notes Es veu a
Jackson 2.x L'estàndard; integrat a Spring 11-07
Gson Google; més simple, menys potent 11-07 (esmentat)
JSON-B Estàndard de Jakarta 11-07 (esmentat)

Logging

Peça Paper Es veu a
SLF4J Façana: l'API contra la qual programes 11-07
Logback Implementació per defecte de Spring Boot 11-07
Log4j2 Implementació alternativa, molt ràpida 11-07 (i §14)
java.util.logging El del JDK; sense dependències, limitat 06-07

Utilitats

Llibreria Què aporta Es veu a
Lombok Genera codi repetitiu en compilació 11-07
Guava Col·leccions, memòria cau, utilitats (Google) 11-07 (panorama)
Apache Commons Lang / IO Utilitats de String, fitxers, reflexió 11-07 (panorama)
MapStruct Mapejadors entitat ↔ DTO en compilació 11-07 (panorama)
Caffeine Memòria cau en memòria d'alt rendiment 11-07 (panorama)

Documentació i operació

Llibreria Què aporta Es veu a
springdoc-openapi Documentació OpenAPI/Swagger automàtica 11-07, 12-04
Micrometer Mètriques 11-07, 12-07
Resilience4j Reintents, curtcircuits, limitadors 11-07, 12-07
Flyway / Liquibase Migracions d'esquema versionades 11-03, 12-06

Amb aquest mapa al davant, l'ecosistema deixa de ser una llista infinita de noms i passa a ser vuit decisions, cadascuna amb una opció per defecte raonable.

  1. Com es tria una dependència

Afegir una línia al pom.xml costa cinc segons i compromet el teu equip durant anys. Aquests són els criteris que es fan servir de veritat.

Criteri Què mirar Senyal d'alarma
Manteniment actiu Data de l'última versió, incidències obertes i tancades, ritme de publicació Sense versions des de fa >2 anys; incidències sense resposta
Llicència Apache 2.0, MIT, BSD són segures. GPL/AGPL contaminen. Revisa-ho sempre GPL en producte comercial tancat; llicència absent
Adopció Nombre d'usos a Maven Central, estrelles, preguntes resoltes en fòrums Deu usuaris al món; ningú no ha tingut el teu problema
Mida i transitivitat Quants jars arrossega? mvn dependency:tree Una utilitat de 20 KB que arrossega 30 MB
Alternativa al JDK Ho fa ja java.util, java.time, java.net.http? Sí, i tot i així afegeixes la dependència
Compatibilitat Versió mínima de Java, jakarta.* enfront de javax.* Requereix Java 8 i no ha migrat a jakarta
Seguretat Té CVE oberts? Publica avisos? Amb quina rapidesa pedaça? Vulnerabilitats conegudes sense corregir
Documentació Hi ha guia d'inici, javadoc, exemples? Només un README de tres línies
Cost de sortida Si demà desapareix, quant costa substituir-la? Impregna tot el codi

Una llista de comprovació pràctica abans d'escriure la dependència:

[ ] La necessito de veritat? No ho fa ja el JDK o alguna cosa que ja tinc?
[ ] La llicencia es compatible amb el meu producte?
[ ] Ha publicat versio en els ultims 12 mesos?
[ ] Te CVE oberts sense corregir?
[ ] Quantes dependencies transitives arrossega?
[ ] Es compatible amb la meva versio de Java i amb jakarta.*?
[ ] Hi ha una alternativa mes petita o mes estandard?
[ ] Se com la trauria si calgues?

Si dubtes en més de dues caselles, no l'afegeixis encara.

  1. La pregunta prèvia: la necessito de veritat?

Abans de tots els criteris anteriors hi ha una pregunta que es salta massa gent.

El JDK modern és molt més ric del que la gent recorda. Moltíssimes dependències històriques ja no calen:

Se solia afegir Avui ja és al JDK Des de
Joda-Time java.time Java 8
Apache HttpClient (per al bàsic) java.net.http.HttpClient Java 11
Commons IO (per al bàsic) java.nio.file.Files Java 7
Guava Lists.newArrayList List.of, new ArrayList<>() Java 9
Commons Lang StringUtils.isBlank String.isBlank() Java 11
Una llibreria per llegir un fitxer sencer Files.readString(path) Java 11
record-like generat per Lombok record Java 16
Base64 de Commons Codec java.util.Base64 Java 8

I el contrapès: tampoc no escriguis tu allò que és notòriament difícil de fer bé. Criptografia, anàlisi de dates amb zones horàries, anàlisi de JSON, anàlisi de CSV amb cometes i salts de línia incrustats (recorda el teu LectorCsv de 07-07 i tots els casos límit que no cobria), i qualsevol cosa relacionada amb seguretat. Aquí la dependència madura és sempre millor que la teva implementació.

La regla pràctica: escriu tu allò que és específic del teu negoci; delega allò que és genèric i difícil.

  1. Maven Central i les coordenades

Quan afegeixes una dependència, d'on surt el jar?

Maven Central és el repositori públic d'artefactes Java, mantingut per Sonatype. Conté milions de versions de centenars de milers de llibreries, i és la destinació per defecte de Maven i Gradle. Quan escrius una dependència i executes mvn package, Maven la descarrega de Central i la desa al teu repositori local (~/.m2/repository) per no tornar-la a baixar.

Cada artefacte s'identifica amb tres coordenades:

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.17.1</version>
</dependency>
Coordenada Què és Convenció
groupId L'organització o projecte Domini invertit: org.springframework.boot
artifactId El mòdul concret Nom curt: spring-boot-starter-web
version La versió publicada Versionat semàntic: 3.3.2

S'escriuen abreujades com groupId:artifactId:version, per exemple com.fasterxml.jackson.core:jackson-databind:2.17.1. Veuràs aquesta notació a les traces de Maven, als informes de seguretat i a tota la documentació.

I el camí físic és predictible: groupId amb els punts convertits en carpetes, després artifactId, després version. El jar anterior viu a:

~/.m2/repository/com/fasterxml/jackson/core/jackson-databind/2.17.1/jackson-databind-2.17.1.jar

Saber això és útil de veritat el dia que Maven et digui que no troba un artefacte: pots anar a aquella carpeta i veure si hi és, si està corrupte, o si només hi ha un fitxer .lastUpdated (símptoma clàssic de descàrrega fallida que s'arregla esborrant la carpeta i executant mvn -U).

Tot això es desenvolupa a 11-05. Aquí només necessites el vocabulari.

  1. Versionat semàntic

La majoria de l'ecosistema Java segueix el versionat semàntic (SemVer), amb el format MAJOR.MENOR.PEDAÇ:

Part S'incrementa quan Compatibilitat Exemple
MAJOR Hi ha canvis que trenquen Trenca 2.7.183.0.0
MENOR S'afegeix funcionalitat compatible Compatible 3.2.03.3.0
PEDAÇ Es corregeixen errors Compatible 3.3.13.3.2

Els sufixos habituals, de menys a més estable:

Sufix Significat
-SNAPSHOT En desenvolupament, canvia sense avisar. Mai en producció
-M1, -M2 Fita (milestone), molt preliminar
-RC1 Candidata a versió, gairebé definitiva
(sense sufix) Versió alliberada (GA), immutable per sempre

Dues conseqüències pràctiques:

  1. Pujar de PEDAÇ o MENOR hauria de ser segur, i és el que fas contínuament per incorporar correccions de seguretat.
  2. Pujar de MAJOR requereix llegir les notes de migració. L'exemple canònic i molt actual: Spring Boot 2.x → 3.x va canviar tots els paquets javax.* per jakarta.* i exigeix Java 17. És el motiu que en aquest curs tot el de persistència sigui jakarta.persistence i no javax.persistence. Si copies un exemple d'internet amb javax.persistence, és de Spring Boot 2 i no et compilarà.

  1. El cost de la seguretat de la cadena de subministrament

Aquí ve la part incòmoda.

Quan afegeixes una dependència, no afegeixes un jar: afegeixes un arbre. Un spring-boot-starter-web porta de l'ordre de trenta artefactes transitius. Un projecte empresarial típic té entre 100 i 400 jars dels quals tu n'has escrit zero.

Cadascun d'aquests jars executa codi amb els mateixos permisos que la teva aplicació. Pot llegir els teus fitxers, obrir connexions de xarxa i accedir a les teves variables d'entorn. I cap no l'has revisat.

Això s'anomena risc de la cadena de subministrament de programari (software supply chain), i té tres formes:

Risc En què consisteix Exemple
Vulnerabilitat coneguda Una fallada publicada (CVE) en una versió que tu fas servir Log4Shell, Spring4Shell
Dependència abandonada Ningú no pedaça; la vulnerabilitat no es corregirà mai Llibreries sense versió des del 2018
Compromís de l'artefacte Algú publica codi maliciós en una llibreria legítima Casos documentats a npm i PyPI

  1. Log4Shell: què va passar de veritat

El desembre del 2021 es va publicar CVE-2021-44228, sobrenomenada Log4Shell, a Apache Log4j 2, una de les llibreries de logging més usades del món Java.

El resum tècnic, sense dramatisme: Log4j 2 admetia als missatges de log una substitució de variables, i una de les formes admeses permetia fer una cerca JNDI contra un servidor remot. Conseqüència: si una aplicació registrava al log un text controlat per l'atacant —una capçalera HTTP, un nom d'usuari, un User-Agent— l'atacant podia provocar que el servidor descarregués i executés codi seu. Execució remota de codi amb una línia de text.

Per què va ser tan greu:

  • Trivial d'explotar: n'hi havia prou amb enviar una cadena en un camp qualsevol que acabés en un log.
  • Omnipresent: Log4j 2 era en desenes de milers de productes, moltes vegades com a dependència transitiva que l'equip ni sabia que tenia.
  • Difícil d'inventariar: la pregunta «tenim Log4j?» va resultar no ser fàcil de respondre a la majoria de les organitzacions. I aquesta va ser la lliçó real.

El que la indústria va aprendre, i que a tu t'afecta directament:

  1. Has de saber què tens. D'aquí l'auge del SBOM (Software Bill of Materials), l'inventari de components d'una aplicació.
  2. Has de poder actualitzar de pressa. Si actualitzar una dependència requereix tres setmanes de proves manuals perquè no hi ha proves automàtiques, la teva finestra d'exposició són tres setmanes. Això connecta directament amb el mòdul 11 al complet: sense Maven no pots canviar una versió amb una línia, i sense JUnit no pots verificar que el canvi no ha trencat res.
  3. Has de vigilar contínuament. Un projecte segur avui té vulnerabilitats d'aquí a sis mesos sense canviar una línia de codi, perquè les vulnerabilitats es descobreixen en codi que ja existia.

Avís important. El que s'explica aquí és el que un desenvolupador ha de saber per no prendre decisions ingènues. En un projecte real, la política de dependències, l'anàlisi de vulnerabilitats i la resposta davant d'incidents són responsabilitat de l'equip o el responsable de seguretat de l'organització, amb eines i processos propis. El teu paper és mantenir l'arbre de dependències sota control, actualitzar quan t'ho indiquin i no introduir dependències sense criteri. Les pràctiques de seguretat de l'aplicació es tracten a 12-07.

  1. Auditar dependències a la pràctica

Tres eines que faràs servir des de 11-05.

1. Veure l'arbre complet. Aquesta és la primera i la que més es fa servir:

mvn dependency:tree

Sortida (retallada) d'un projecte Spring Boot amb web:

[INFO] com.nexussoftware:bibliotech:jar:1.0.0-SNAPSHOT
[INFO] +- org.springframework.boot:spring-boot-starter-web:jar:3.3.2:compile
[INFO] |  +- org.springframework.boot:spring-boot-starter:jar:3.3.2:compile
[INFO] |  |  +- org.springframework.boot:spring-boot-starter-logging:jar:3.3.2:compile
[INFO] |  |  |  +- ch.qos.logback:logback-classic:jar:1.5.6:compile
[INFO] |  |  |  |  \- ch.qos.logback:logback-core:jar:1.5.6:compile
[INFO] |  |  |  \- org.slf4j:jul-to-slf4j:jar:2.0.13:compile
[INFO] |  +- org.springframework.boot:spring-boot-starter-json:jar:3.3.2:compile
[INFO] |  |  \- com.fasterxml.jackson.core:jackson-databind:jar:2.17.2:compile
[INFO] |  \- org.springframework.boot:spring-boot-starter-tomcat:jar:3.3.2:compile

Aquí veus de cop tres coses que aquest mòdul explicarà: que Spring Boot ja porta Logback i SLF4J (11-07), que ja porta Jackson (11-07) i que ja porta Tomcat incrustat (12-04). I veus que un jar que tu no vas declarar, logback-core, és a la teva aplicació.

Per buscar qui arrossega un artefacte concret:

mvn dependency:tree -Dincludes=com.fasterxml.jackson.core:jackson-databind

2. Buscar vulnerabilitats conegudes. El plugin d'OWASP contrasta el teu arbre amb la base de dades pública de vulnerabilitats:

mvn org.owasp:dependency-check-maven:check

Genera un informe HTML a target/ amb els CVE trobats i la seva gravetat. En un projecte real això s'executa a la integració contínua, no a mà.

3. Veure què està desactualitzat.

mvn versions:display-dependency-updates

Et llista, dependència a dependència, quina versió fas servir i quina és l'última disponible. Executar-lo cada poques setmanes i actualitzar els pedaços és una de les pràctiques d'higiene més rendibles que existeixen.

  1. Quin framework aprendre primer

Si has arribat fins aquí, la llista d'opcions pot paralitzar-te. El criteri per triar el primer no és tècnic, és d'aprenentatge:

  1. Aprèn el que més es faci servir. No perquè sigui el millor, sinó perquè quan t'encallis —i t'encallaràs— hi haurà algú que ja es va encallar igual i ho va escriure. La documentació, els cursos i les respostes són un recurs real.
  2. Aprèn-ne un bé abans que tres a mitges. Els conceptes —IoC, DI, ORM, AOP, context de persistència— es transfereixen. La sintaxi, no. Qui domina Spring aprèn Quarkus en dues setmanes; qui ha tocat els tres per sobre no en domina cap.
  3. Aprèn amb un projecte real, no amb exemples aïllats. Per això aquest mòdul va sobre BiblioTech, i per això hi ha un mòdul 12 sencer per integrar-ho tot.

  1. Per què aquest curs tria Spring Boot

Amb honestedat, tres raons i un advertiment.

  • És el que hi ha al mercat. Una majoria molt àmplia de les ofertes de feina de back-end Java esmenten Spring o Spring Boot. És el coneixement amb més valor immediat.
  • Cobreix totes les categories del mapa. Amb Spring Boot toques DI, web, persistència, proves, configuració, seguretat i observabilitat amb un model coherent. Aprens vuit coses en un ecosistema en comptes de en vuit.
  • La seva màgia és exactament la que ja entens. Anotacions, reflexió, proxies dinàmics. Estàs en la millor posició possible per aprendre'l sense que sigui màgia.

L'advertiment: Spring no és la resposta a tot. Per a un CLI petit és un canó per matar mosques, i fins a 12-03 veuràs que una aplicació de consola ben estructurada no el necessita. Per a funcions serverless amb arrencada en fred, Quarkus o Micronaut són millors. I per a un servei que només fa tres consultes SQL, jOOQ o JdbcTemplate poden ser més adequats que Hibernate. Triar bé és part de l'ofici; i per triar cal conèixer.

  1. El pla del mòdul 11

Aquest mòdul té una estructura deliberada: cada lliçó salda un deute del mòdul 10 i presenta una eina de forma completa i autònoma. La integració en un projecte real és el mòdul 12.

graph TD
    L1["11-01<br/>Introduccio<br/>als frameworks"] --> L2["11-02<br/>Spring<br/>IoC, AOP, Boot"]
    L2 --> L3["11-03<br/>Hibernate<br/>JPA sobre H2"]
    L3 --> L4["11-04<br/>JUnit 5<br/>les primeres proves"]
    L4 --> L5["11-05<br/>Maven<br/>construccio"]
    L5 --> L6["11-06<br/>Mockito<br/>proves avancades"]
    L6 --> L7["11-07<br/>Jackson, Lombok<br/>SLF4J i ecosistema"]
    L7 --> M12["Modul 12<br/>Aplicacio real"]
Lliçó Eina Deute que salda
11-02 Spring Framework i Spring Boot El ContenidorSimple casolà i la configuració per entorn
11-03 Hibernate / JPA El CSV com a persistència
11-04 JUnit 5 L'absència total de proves
11-05 Maven El javac a mà i les dependències
11-06 Mockito Provar allò que depèn de xarxa, disc i rellotge
11-07 Jackson, Lombok, SLF4J El JSON amb indexOf, el codi repetitiu, java.util.logging

Al final del mòdul, BiblioTech serà un projecte Maven amb Spring, persistència JPA sobre H2, proves amb JUnit i Mockito, JSON amb Jackson i logging amb SLF4J. Encara no serà una aplicació completa —això és el mòdul 12—, però totes les seves peces seran les de veritat.

  1. Errors comuns i consells

Error: creure que un framework t'eximeix d'entendre el que hi ha a sota. És exactament al revés. El framework automatitza; quan l'automatització falla, només pot arreglar-ho qui entén el mecanisme. Si @Transactional no reverteix, necessites saber de proxies i de transaccions de base de dades.

Error: afegir dependències sense avaluar-les. «Necessito ordenar una llista, afegiré Guava.» No. Mira primer el JDK, després el que ja tens a l'arbre, i només després Maven Central.

Error: copiar exemples d'internet sense mirar la versió. El símptoma inequívoc: javax.persistence en comptes de jakarta.persistence, o WebSecurityConfigurerAdapter, que es va eliminar. Són de Spring Boot 2 i no compilen al 3. Comprova sempre la data i la versió de l'exemple.

Error: fixar versions de dependències que gestiona el BOM. Quan facis servir spring-boot-starter-parent, no posis <version> a les dependències que ell gestiona: li estàs traient la feina de garantir que les versions són compatibles entre si. S'explica a 11-05.

Error: fer servir rangs de versions o LATEST. Trenca la reproductibilitat: la mateixa etiqueta de git compila diferent segons el dia. Fixa sempre versions concretes.

Error: no actualitzar mai «perquè funciona». Una aplicació que no es toca durant tres anys acumula desenes de vulnerabilitats conegudes. I quan per fi cal actualitzar, el salt és tan gran que es converteix en un projecte.

Consell: distingeix el nucli de la lampisteria. Mantén el teu domini (entitats, regles de negoci) com més net millor d'anotacions del framework. La lògica de les multes de BiblioTech ha de poder-se provar sense arrencar Spring. Aquest principi s'aprofundeix a 12-02.

Consell: aprèn a llegir un dependency:tree. És l'eina que més vegades et traurà d'un compromís: conflictes de versions, jars duplicats, classes que apareixen dues vegades, i la pregunta de seguretat «tinc aquesta llibreria?».

Consell: quan alguna cosa del framework et sembli màgia, busca el mecanisme. Pregunta't: és una anotació llegida per reflexió? És un proxy? És codi generat en compilació? Gairebé sempre és una de les tres, i llavors deixa de ser màgia.

Consell: mira les dependències d'un starter abans d'afegir-lo. Un spring-boot-starter-web porta Tomcat, Jackson, validació i logging. Saber-ho evita afegir Jackson pel teu compte amb una altra versió i provocar un conflicte.

  1. Exercicis

Exercici 1: classificar i justificar

Per a cada element de la llista, indica si és llibreria o framework, i justifica la resposta amb el criteri de "qui crida qui". En els casos ambigus, explica per què ho són.

  1. java.util.Collections
  2. JUnit 5
  3. Jackson ObjectMapper
  4. Hibernate
  5. SLF4J
  6. Spring Boot
  7. El ContenidorSimple que vas escriure a 10-03
  8. El ProxyAuditoria que vas escriure a 10-03

Exercici 2: avaluar una dependència real

Nexus Software necessita generar codis de barres per a les etiquetes dels llibres de BiblioTech. Un company proposa afegir una llibreria que va trobar. Escriu l'anàlisi que faries abans d'acceptar-la, fent servir la llista de comprovació de la lliçó, i decideix. Dades disponibles:

  • groupId:artifactIdcom.exemple:barcode-magic
  • Última versió: 0.4.1, publicada fa 3 anys
  • Llicència: no consta al POM
  • Usos a Maven Central: 7 projectes
  • Dependències transitives: 14 jars, inclosos un motor gràfic complet i una llibreria XML
  • Documentació: un README de 8 línies
  • Un CVE de gravetat mitjana obert des de fa 14 mesos

Exercici 3: el mapa invers

Per a cadascun d'aquests comportaments "màgics" que veuràs a les properes lliçons, indica quin dels quatre mecanismes de l'apartat 6 el fa possible i què vas escriure tu al mòdul 10 que s'hi assembla.

  1. Escrius @Service sobre GestorPrestecs i Spring l'instancia sol.
  2. Escrius @Transactional i la base de dades reverteix en llançar una excepció.
  3. Escrius @Getter de Lombok i apareix un getTitol() que tu no vas escriure.
  4. Declares interface PrestecRepository extends JpaRepository<Prestec, Long> sense implementar-la i funciona.
  5. Escrius @Test i el mètode s'executa sense main.
  6. Escrius @JsonProperty("isbn_13") i Jackson fa servir aquest nom al JSON.

Solucions

Solució 1

Element Tipus Justificació
java.util.Collections Llibreria Tu crides Collections.sort(...) quan vols. Control totalment teu.
JUnit 5 Framework No hi ha main. JUnit descobreix els teus @Test per reflexió i els invoca. Principi de Hollywood pur.
Jackson ObjectMapper Llibreria Tu crides writeValueAsString(...). Encara que llegeixi anotacions teves, el flux el controles tu.
Hibernate Tots dos És llibreria quan crides entityManager.find(...); és framework quan la comprovació de canvis automàtica detecta que vas modificar una entitat gestionada i emet un UPDATE sense que tu cridis res. Aquest segon comportament és control invertit (es veu a 11-03).
SLF4J Llibreria (façana) Tu crides log.info(...). A més és una façana: la implementació es tria en temps d'execució, però el flux continua sent teu.
Spring Boot Framework Arrenca ell, escaneja les teves classes, les instancia, les injecta i crida el teu CommandLineRunner o el teu controlador quan arriba una petició.
El teu ContenidorSimple Framework (en miniatura) Escaneja @Component, decideix l'ordre de construcció i instancia les teves classes. Tu no crides new: el crida ell.
El teu ProxyAuditoria Framework (en miniatura) Intercepta la crida, executa codi abans i després, i decideix quan invocar el teu mètode. El flux passa per ell.

La conclusió que importa: vas escriure dos frameworks en miniatura sense anomenar-los així.

Solució 2

Aplicant la llista de comprovació:

Casella Resultat Comentari
La necessito de veritat? Generar un codi de barres correcte (checksums EAN-13, quiet zones) és difícil de fer bé a mà. És un cas legítim de dependència.
Llicència compatible? NO Sense llicència declarada, per defecte no hi ha permís d'ús. Això per si sol bloqueja la decisió.
Versió en els últims 12 mesos? NO 3 anys sense publicar. Morta a efectes pràctics.
CVE oberts? NO Un de gravetat mitjana, sense corregir en 14 mesos: confirma l'abandonament.
Transitivitat raonable? NO 14 jars, amb un motor gràfic i una llibreria XML, per generar una imatge de codi de barres. Desproporcionat i superfície d'atac enorme.
Compatible amb el meu Java? Desconegut Versió 0.x: l'API pot canviar sense previ avís, encara que l'abandonament ho fa irrellevant.
Alternativa millor? ZXing (Apache 2.0, de Google, mantinguda, molt usada) o Barcode4J són opcions madures per al mateix.
Cost de sortida? Baix Es faria servir des d'un únic punt, darrere d'una interfície pròpia. És l'única cosa positiva.

Decisió: rebutjar. Quatre caselles crítiques fallen, i la llicència sola ja bastaria. Contraproposta: fer servir ZXing, i fer-ho darrere d'una interfície pròpia (GeneradorEtiquetes), de manera que la llibreria concreta quedi aïllada en una sola classe i el cost de canviar-la en el futur sigui d'una implementació. I afegir l'anàlisi de dependències a la integració contínua perquè el proper CVE es detecti sol.

Nota professional: el punt de la llicència no es negocia per criteri tècnic. En una empresa, un jar sense llicència declarada és un problema legal, i aquesta conversa l'ha de tenir el responsable corresponent, no el desenvolupador pel seu compte.

Solució 3

Comportament Mecanisme El teu equivalent del mòdul 10
1. @Service instancia sol Anotació + reflexió. Spring escaneja el classpath, troba la classe anotada, llegeix el seu constructor amb getDeclaredConstructors(), resol els paràmetres i crida newInstance El ContenidorSimple amb @Component, exactament el mateix bucle (10-03)
2. @Transactional reverteix Proxy dinàmic. L'objecte que hi ha al contenidor no és la teva classe: és un embolcall que obre transacció, invoca el teu mètode i confirma o reverteix segons hi hagi excepció ProxyAuditoria i ProxyReintents: l'InvocationHandler que executa codi abans i després de metode.invoke(...) (10-03)
3. @Getter de Lombok Generació de codi en compilació (processador d'anotacions). No hi ha reflexió ni proxy: el .class ja conté el mètode. Pots veure-ho amb javap El processador d'anotacions estudiat a 10-02
4. JpaRepository sense implementació Proxy dinàmic sobre interfície més anàlisi del nom del mètode. Proxy.newProxyInstance genera una implementació al vol que tradueix findByIsbn a una consulta Proxy.newProxyInstance sobre interfícies, tal qual el vas escriure (10-03)
5. @Test s'executa sense main Anotació + reflexió. JUnit Platform descobreix les classes, filtra els mètodes amb isAnnotationPresent(Test.class) i els invoca amb Method.invoke L'ExportadorAnotat, que recorria membres buscant una anotació i actuava (10-03)
6. @JsonProperty("isbn_13") Anotació + reflexió. Jackson introspecciona la classe, llegeix l'anotació del camp i fa servir el seu valor com a clau del JSON @CampCsv("nom") llegida per l'ExportadorAnotat — és literalment el mateix disseny (10-02, 10-03)

Si has pogut completar aquesta taula, l'objectiu de la lliçó està assolit: no queda màgia, queden quatre mecanismes que ja coneixes aplicats a escala industrial.

Conclusió

Els frameworks han deixat de ser una caixa negra abans fins i tot de fer servir el primer.

Saps distingir llibreria de framework per l'única pregunta que importa —qui crida qui— i reconeixes el principi de Hollywood quan el veus: un mètode @Test sense main, un @Service que s'instancia sol, una entitat que es desa sense que cridis save. I entens la inversió de control no com una definició de manual sinó com el canvi concret que vas fer a GestorPrestecs: de crear les seves pròpies dependències amb new a declarar-les al constructor i deixar que un altre les resolgui — amb les quatre conseqüències que això va tenir (es pot provar, es pot canviar d'implementació, es pot configurar per entorn i el rellotge deixa de ser el del sistema).

Saps què compres i què pagues. Compres codi no diferenciador ja resolt, convencions que qualsevol desenvolupador entén, un ecosistema integrat i —el més subestimat— pedaços de seguretat mantinguts per altres. Pagues corba d'aprenentatge, acoblament arquitectònic, comportament implícit difícil de depurar i pes. I saps que la resposta correcta a «framework sí o no?» sempre comença per «depèn del context».

I sobretot, saps com se sosté la màgia: anotacions amb @Retention(RUNTIME) que són etiquetes inertes; reflexió que les llegeix i actua; proxies dinàmics que embolcallen els teus objectes per afegir comportament sense tocar el teu codi —amb el detall, que ja et trobaràs, que la crida interna no passa pel proxy i que CGLIB no pot amb allò que és final—; i generació de codi, en compilació amb processadors d'anotacions o en execució amb bytecode. Quatre mecanismes. Els quatre els has escrit o estudiat. I tens el mapa complet d'allò que vas fer a mà → allò que fa el framework de veritat, que és alhora el teu full de ruta del mòdul i el teu manual de diagnòstic quan alguna cosa falli.

Tens el mapa de l'ecosistema ordenat en vuit categories amb una opció per defecte a cadascuna, de manera que la llista infinita de noms es converteix en vuit decisions. I tens criteri per a la decisió que prendràs desenes de vegades: afegir o no una dependència. Amb la pregunta prèvia al davant —no ho fa ja el JDK?, perquè java.time, HttpClient, Files.readString, String.isBlank i els record han deixat obsoletes moltes dependències clàssiques— i amb els criteris reals al darrere: manteniment, llicència, adopció, transitivitat, seguretat i cost de sortida.

Coneixes Maven Central, les coordenades groupId:artifactId:version, el camí predictible dins de ~/.m2 i el versionat semàntic amb la seva conseqüència més pràctica avui: el salt de Spring Boot 2 a 3 va canviar javax.* per jakarta.*, i per això un exemple copiat d'internet amb javax.persistence senzillament no et compilarà.

I entens el risc de la cadena de subministrament: que un projecte mitjà té centenars de jars que ningú no ha revisat executant-se amb els teus permisos, que Log4Shell va demostrar que la pregunta difícil no era pedaçar sinó saber què tens, i que la capacitat d'actualitzar de pressa depèn exactament de les dues eines d'aquest mòdul —Maven per canviar una versió amb una línia i JUnit per verificar que no has trencat res—. Amb l'advertiment clar que, en un projecte real, la política de dependències i la resposta davant de vulnerabilitats corresponen al responsable de seguretat, i que les pràctiques de seguretat de l'aplicació arriben a 12-07.


El pla està fixat i cada lliçó salda un deute. El primer és el més gran: aquell ContenidorSimple de cent cinquanta línies que vas escriure per no cridar new, i al qual li falta absolutament tota la resta — àmbits, cicle de vida, perfils, propietats externalitzades, resolució d'ambigüitat i transaccions.

A la propera lliçó, BiblioTech llença aquest contenidor a les escombraries i adopta el que porten vint anys polint deu mil desenvolupadors. Veuràs l'ApplicationContext, les tres formes d'injecció i per què només una és recomanable, els estereotips, el cicle de vida d'un bean, els àmbits, els perfils dev i prod, les propietats tipades que substitueixen la teva Configuracio de 07-07, i l'autoconfiguració de Spring Boot explicada de veritat — no com a màgia, sinó com un conjunt de condicions que pots llegir i depurar.

I quan arribis a @Transactional, no veuràs una anotació misteriosa: veuràs el teu propi ProxyAuditoria, amb vint anys de poliment a sobre.

Comencem per Spring.

Curs de Programació en Java

Mòdul 1: Introducció a Java

Mòdul 2: Flux de control

Mòdul 3: Programació orientada a objectes

Mòdul 4: Programació orientada a objectes avançada

Mòdul 5: Estructures de dades i col·leccions

Mòdul 6: Gestió d'excepcions

Mòdul 7: Entrada/sortida de fitxers

Mòdul 8: Multifil i concurrència

Mòdul 9: Xarxes

Mòdul 10: Temes avançats

Mòdul 11: Frameworks i llibreries de Java

Mòdul 12: Construcció d'aplicacions del món real

© Copyright 2026. Tots els drets reservats