No VRaptor3 a injeção de dependencia ficou bem mais fácil, os interceptadores que eram os responsáveis para injetar a dependencia sumiram e agora fica tudo a cargo do container, que pode ser o Spring ou o Pico.
A facilidade na injeção de dependencia tem um custo, como não é mais controlado pelo programador que cria o interceptor sempre que declaramos uma dependencia no construtor de um @Component, @Resource ou @Intercepts ele é injetado no inicio, logo na construção, porem as vezes o fluxo de um requisição faz com que não usemos algumas destas injeções de dependencia, disperdiçando recursos valiosos.
Por exemplo, vamos supor o seguinte @Resource abaixo, que cadastra produtos
- import java.util.List;
 - import org.hibernate.Session;
 - import br.com.caelum.vraptor.Result;
 - import br.com.caelum.vraptor.view.Results;
 - public class ProdutoController {
 - /**
 - * O recurso que queremos poupar.
 - */
 - private final Session session;
 - private final Result result;
 - public ProdutoController(final Session session, final Result result) {
 - this.session = session;
 - this.result = result;
 - }
 - /**
 - * apenas renderiza o formulário
 - */
 - public void form() {}
 - public List<Produto> listar() {
 - return session.createCriteria(Produto.class).list();
 - }
 - public Produto adiciona(Produto produto) {
 - session.persist(produto);
 - result.use(Results.logic()).redirectTo(getClass()).listar();
 - return produto;
 - }
 - }
 
Sempre que alguem faz uma requisição a qualquer lógica dentro do recurso ProdutoController uma Session é aberta, porem note que abrir o formulário para adicionar produtos não requer sessão com o banco, ele apenas renderiza uma página, cada vez que o formulário de produtos é aberto um importante e caro recurso do sistema esta sendo requerido, e de forma totalmente ociosa.
Como agir neste caso ? isolar o formulário poderia resolver este problema mais recairia em outro, da mantenabilidade.
O ideal é que este recurso só fosse realmente injetado no tempo certo (Just in Time) como seria possivel fazer isso ? a solução é usar proxy dinamicos, enviando uma session que só realmente abrirá a conexão com o banco quando um de seus métodos for invocado
- import java.lang.reflect.Method;
 - import javax.annotation.PreDestroy;
 - import org.hibernate.classic.Session;
 - import org.hibernate.SessionFactory;
 - import net.vidageek.mirror.dsl.Mirror;
 - import br.com.caelum.vraptor.ioc.ApplicationScoped;
 - import br.com.caelum.vraptor.ioc.Component;
 - import br.com.caelum.vraptor.ioc.ComponentFactory;
 - import br.com.caelum.vraptor.ioc.RequestScoped;
 - import br.com.caelum.vraptor.proxy.MethodInvocation;
 - import br.com.caelum.vraptor.proxy.Proxifier;
 - import br.com.caelum.vraptor.proxy.SuperMethod;
 - /**
 - * <b>JIT (Just-in-Time) {@link Session} Creator</b> fábrica para o componente {@link Session}
 - * gerado de forma LAZY ou JIT(Just-in-Time) a partir de uma {@link SessionFactory}, que
 - * normalmente se encontra em um ecopo de aplicativo @{@link ApplicationScoped}.
 - *
 - * @author Tomaz Lavieri
 - * @since 1.0
 - */
 - @RequestScoped
 - public class JITSessionCreator implements ComponentFactory<Session> {
 - private static final Method CLOSE = new Mirror().on(Session.class).reflect().method("close").withoutArgs();
 - private final SessionFactory factory;
 - /** Guarda a Proxy Session */
 - private final Session proxy;
 - /** Guarada a Session real. */
 - private Session session;
 - public JITSessionCreator(final SessionFactory factory, final Proxifier proxifier) {
 - this.factory = factory;
 - this.proxy = proxify(Session.class, proxifier); // *1*
 - }
 - /**
 - * Cria o JIT Session, que repassa a invocação de qualquer método, exceto
 - * {@link Object#finalize()} e {@link Session#close()}, para uma session real, criando
 - * uma se necessário.
 - */
 - private Session proxify(Class<? extends Session> target, Proxifier proxifier) {
 - return proxifier.proxify(target, new MethodInvocation<Session>() {
 - @Override // *2*
 - if (method.equals(CLOSE) || (method.equals(FINALIZE) && session == null)) {
 - return null; //skip
 - }
 - return new Mirror().on(getSession()).invoke().method(method).withArgs(args);
 - }
 - });
 - }
 - public Session getSession() {
 - if (session == null) // *3*
 - session = factory.openSession();
 - return session;
 - }
 - @Override
 - public Session getInstance() {
 - return proxy; // *4*
 - }
 - @PreDestroy
 - public void destroy() { // *5*
 - if (session != null && session.isOpen()) {
 - session.close();
 - }
 - }
 - }
 
Explicando alguns pontos chaves, comentados com // *N*
- O Proxfier é um objeto das libs do vrapor que auxilia na criação de objetos proxys ele é responsável por escolher a biblioteca que implementa o proxy dinamico, e então invocar via callback um método interceptor, como falamo abaixo.
 - Neste ponto temos a implementação do nosso interceptor, sempre que um método for envocado em nosso proxy, esse intereptor é invocado primeiro, ele filtra as chamada ao método finalize caso a session real ainda não tenha sido criada, isso evita criar a session apenas para finaliza-la.
O método close também é filtrao, isso é feito para evitar criar uma session apenas para fecha-la, e também por que o nosso SessionCreator é que é o responsavel por fechar a session ao final do scopo, quando a request acabar.
Todos os outros métodos são repassados para uma session através do método getSession() onde é realmente que acontece o LAZY ou JIT. - Aqui é onde acontece a mágia, da primeira vez que getSession() é invocado a sessão é criada, e então repassada, todas as outras chamadas a getSession() repassam a sessão anteriormente criada, assim, se getSession() nunca for envocado, ou seja, se nenhum método for envocado no proxy, getSession() nunca será invocado, e a sessão real não será criada.
 - O retorno desse ComponentFactory é a Session proxy, que só criará a session real se um de seus métodos for invocado.
 - Ao final do escopo o destroy é invocado, ele verifica se a session real existe, existindo verifica se esta ainda esta aberta, e estando ele fecha, desta forma é possivel garantir que o recurso será sempre liberado.
 
Assim podemos agora pedir uma session sempre que acharmos que vamos precisar de uma, sabendo que o recurso só será realmente solicitado quando formos usar um de seus métodos, salvando assim o recurso.
Esta mesma abordagem pode ser usada para outros recursos caros do sistema.
Os códigos fonte para os ComponentFactory de EntityManager e Session que utilizo podem ser encontrados neste link: http://guj.com.br/posts/list/141500.java
